1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- begin                                       guest_x86_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
10663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Copyright (C) 2004-2012 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 x86 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 32-bit value is being written.
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FUCOMI(P): what happens to A and S flags?  Currently are forced
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to zero.
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x87 FP Limitations:
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * all arithmetic done at 64 bits
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * no FP exceptions, except for handling stack over/underflow
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FP rounding mode observed only for float->int conversions
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     and int->float conversions which could lose accuracy, and
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     for float-to-float rounding.  For all other operations,
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     round-to-nearest is used, regardless.
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FP sin/cos/tan/sincos: C2 flag is always cleared.  IOW the
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     even when it isn't.
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * some of the FCOM cases could do with testing -- not convinced
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     that the args are the right way round.
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FSAVE does not re-initialise the FPU; it should do
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FINIT not only initialises the FPU environment, it also
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     zeroes all the FP registers.  It should leave the registers
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     unchanged.
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SAHF should cause eflags[1] == 1, and in fact it produces 0.  As
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   per Intel docs this bit has no meaning anyway.  Since PUSHF is the
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   only way to observe eflags[1], a proper fix would be to make that
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bit be set by PUSHF.
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The state of %eflags.AC (alignment check, bit 18) is recorded by
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the simulation (viz, if you set it with popf then a pushf produces
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the value you set it to), but it is otherwise ignored.  In
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   particular, setting it to 1 does NOT cause alignment checking to
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   happen.  Programs that set it to 1 and then rely on the resulting
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SIGBUSs to inform them of misaligned accesses will not work.
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Implementation of sysenter is necessarily partial.  sysenter is a
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   kind of system call entry.  When doing a sysenter, the return
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   address is not known -- that is something that is beyond Vex's
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   knowledge.  So the generated IR forces a return to the scheduler,
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which can do what it likes to simulate the systenter, but it MUST
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   set this thread's guest_EIP field with the continuation address
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   before resuming execution.  If that doesn't happen, the thread will
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   jump to address zero, which is probably fatal.
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This module uses global variables and so is not MT-safe (if that
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   should ever become relevant).
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The delta values are 32-bit ints, not 64-bit ints.  That means
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   this module may not work right if run on a 64-bit host.  That should
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   be fixed properly, really -- if anyone ever wants to use Vex to
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   translate x86 code for execution on a 64-bit host.
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   casLE (implementation of lock-prefixed insns) and rep-prefixed
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insns: the side-exit back to the start of the insn is done with
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ijk_Boring.  This is quite wrong, it should be done with
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ijk_NoRedir, since otherwise the side exit, which is intended to
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   restart the instruction for whatever reason, could go somewhere
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   entirely else.  Doing it right (with Ijk_NoRedir jumps) would make
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   no-redir jumps performance critical, at least for rep-prefixed
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instructions, since all iterations thereof would involve such a
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   jump.  It's not such a big deal with casLE since the side exit is
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   only taken if the CAS fails, that is, the location is contended,
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which is relatively unlikely.
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XXXX: Nov 2009: handling of SWP on ARM suffers from the same
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   problem.
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Note also, the test for CAS success vs failure is done using
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Iop_CasCmp{EQ,NE}{8,16,32,64} rather than the ordinary
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Iop_Cmp{EQ,NE} equivalents.  This is so as to tell Memcheck that it
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shouldn't definedness-check these comparisons.  See
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   COMMENT_ON_CasCmpEQ in memcheck/mc_translate.c for
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   background/rationale.
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Performance holes:
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - fcom ; fstsw %ax ; sahf
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     sahf does not update the O flag (sigh) and so O needs to
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     be computed.  This is done expensively; it would be better
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     to have a calculate_eflags_o helper.
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - emwarns; some FP codes can generate huge numbers of these
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if the fpucw is changed in an inner loop.  It would be
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     better for the guest state to have an emwarn-enable reg
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     which can be set zero or nonzero.  If it is zero, emwarns
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     are not flagged, and instead control just flows all the
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     way through bbs as usual.
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* "Special" instructions.
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This instruction decoder can decode three special instructions
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which mean nothing natively (are no-ops as far as regs/mem are
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   concerned) but have meaning for supporting Valgrind.  A special
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction is flagged by the 12-byte preamble C1C703 C1C70D C1C71D
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   C1C713 (in the standard interpretation, that means: roll $3, %edi;
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   roll $13, %edi; roll $29, %edi; roll $19, %edi).  Following that,
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   one of the following 3 are allowed (standard interpretation in
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   parentheses):
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      87DB (xchgl %ebx,%ebx)   %EDX = client_request ( %EAX )
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      87C9 (xchgl %ecx,%ecx)   %EAX = guest_NRADDR
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      87D2 (xchgl %edx,%edx)   call-noredir *%EAX
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Any other bytes following the 12-byte preamble are illegal and
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   constitute a failure in instruction decoding.  This all assumes
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that the preamble will never occur except in specific code
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fragments designed for Valgrind to catch.
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   No prefixes may precede a "Special" instruction.
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* LOCK prefixed instructions.  These are translated using IR-level
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CAS statements (IRCAS) and are believed to preserve atomicity, even
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from the point of view of some other process racing against a
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   simulated one (presumably they communicate via a shared memory
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   segment).
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Handlers which are aware of LOCK prefixes are:
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_op2_G_E      (add, or, adc, sbb, and, sub, xor)
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_cmpxchg_G_E  (cmpxchg)
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp1         (add, or, adc, sbb, and, sub, xor)
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp3         (not, neg)
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp4         (inc, dec)
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp5         (inc, dec)
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp8_Imm     (bts, btc, btr)
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_bt_G_E       (bts, btc, btr)
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_xadd_G_E     (xadd)
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_basictypes.h"
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_ir.h"
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex.h"
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_guest_x86.h"
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "main_util.h"
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "main_globals.h"
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "guest_generic_bb_to_IR.h"
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "guest_generic_x87.h"
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "guest_x86_defs.h"
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Globals                                              ---*/
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* These are set at the start of the translation of an insn, right
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   down in disInstr_X86, so that we don't have to pass them around
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   endlessly.  They are all constant during the translation of any
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   given insn. */
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* We need to know this to do sub-register accesses correctly. */
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool host_is_bigendian;
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Pointer to the guest code area (points to start of BB, not to the
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn being processed). */
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar* guest_code;
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The guest address corresponding to guest_code[0]. */
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr32 guest_EIP_bbstart;
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The guest address for the instruction currently being
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   translated. */
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr32 guest_EIP_curr_instr;
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The IRSB* into which we're generating code. */
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRSB* irsb;
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Debugging output                                     ---*/
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define DIP(format, args...)           \
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (vex_traceflags & VEX_TRACE_FE)  \
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_printf(format, ## args)
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define DIS(buf, format, args...)      \
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (vex_traceflags & VEX_TRACE_FE)  \
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_sprintf(buf, format, ## args)
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Offsets of various parts of the x86 guest state.     ---*/
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EAX       offsetof(VexGuestX86State,guest_EAX)
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EBX       offsetof(VexGuestX86State,guest_EBX)
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_ECX       offsetof(VexGuestX86State,guest_ECX)
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EDX       offsetof(VexGuestX86State,guest_EDX)
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_ESP       offsetof(VexGuestX86State,guest_ESP)
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EBP       offsetof(VexGuestX86State,guest_EBP)
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_ESI       offsetof(VexGuestX86State,guest_ESI)
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EDI       offsetof(VexGuestX86State,guest_EDI)
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EIP       offsetof(VexGuestX86State,guest_EIP)
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_OP     offsetof(VexGuestX86State,guest_CC_OP)
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_DEP1   offsetof(VexGuestX86State,guest_CC_DEP1)
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_DEP2   offsetof(VexGuestX86State,guest_CC_DEP2)
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_NDEP   offsetof(VexGuestX86State,guest_CC_NDEP)
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FPREGS    offsetof(VexGuestX86State,guest_FPREG[0])
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FPTAGS    offsetof(VexGuestX86State,guest_FPTAG[0])
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_DFLAG     offsetof(VexGuestX86State,guest_DFLAG)
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_IDFLAG    offsetof(VexGuestX86State,guest_IDFLAG)
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_ACFLAG    offsetof(VexGuestX86State,guest_ACFLAG)
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FTOP      offsetof(VexGuestX86State,guest_FTOP)
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FC3210    offsetof(VexGuestX86State,guest_FC3210)
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FPROUND   offsetof(VexGuestX86State,guest_FPROUND)
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CS        offsetof(VexGuestX86State,guest_CS)
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_DS        offsetof(VexGuestX86State,guest_DS)
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_ES        offsetof(VexGuestX86State,guest_ES)
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FS        offsetof(VexGuestX86State,guest_FS)
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_GS        offsetof(VexGuestX86State,guest_GS)
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_SS        offsetof(VexGuestX86State,guest_SS)
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_LDT       offsetof(VexGuestX86State,guest_LDT)
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_GDT       offsetof(VexGuestX86State,guest_GDT)
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_SSEROUND  offsetof(VexGuestX86State,guest_SSEROUND)
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM0      offsetof(VexGuestX86State,guest_XMM0)
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM1      offsetof(VexGuestX86State,guest_XMM1)
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM2      offsetof(VexGuestX86State,guest_XMM2)
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM3      offsetof(VexGuestX86State,guest_XMM3)
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM4      offsetof(VexGuestX86State,guest_XMM4)
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM5      offsetof(VexGuestX86State,guest_XMM5)
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM6      offsetof(VexGuestX86State,guest_XMM6)
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM7      offsetof(VexGuestX86State,guest_XMM7)
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EMWARN    offsetof(VexGuestX86State,guest_EMWARN)
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_TISTART   offsetof(VexGuestX86State,guest_TISTART)
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_TILEN     offsetof(VexGuestX86State,guest_TILEN)
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_NRADDR    offsetof(VexGuestX86State,guest_NRADDR)
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_IP_AT_SYSCALL offsetof(VexGuestX86State,guest_IP_AT_SYSCALL)
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helper bits and pieces for deconstructing the        ---*/
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- x86 insn stream.                                     ---*/
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is the Intel register encoding -- integer regs. */
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_EAX 0
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_ECX 1
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_EDX 2
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_EBX 3
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_ESP 4
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_EBP 5
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_ESI 6
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_EDI 7
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_AL (0+R_EAX)
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_AH (4+R_EAX)
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is the Intel register encoding -- segment regs. */
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_ES 0
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_CS 1
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_SS 2
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_DS 3
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_FS 4
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_GS 5
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add a statement to the list held by "irbb". */
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void stmt ( IRStmt* st )
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( irsb, st );
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate a new temporary of the given type. */
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp newTemp ( IRType ty )
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(isPlausibleIRType(ty));
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return newIRTemp( irsb->tyenv, ty );
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Various simple conversions */
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt extend_s_8to32( UInt x )
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (UInt)((((Int)x) << 24) >> 24);
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt extend_s_16to32 ( UInt x )
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (UInt)((((Int)x) << 16) >> 16);
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Fetch a byte from the guest insn stream. */
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar getIByte ( Int delta )
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return guest_code[delta];
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Extract the reg field from a modRM byte. */
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int gregOfRM ( UChar mod_reg_rm )
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (Int)( (mod_reg_rm >> 3) & 7 );
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Figure out whether the mod and rm parts of a modRM byte refer to a
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register or memory.  If so, the byte will have the form 11XXXYYY,
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   where YYY is the register number. */
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool epartIsReg ( UChar mod_reg_rm )
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool(0xC0 == (mod_reg_rm & 0xC0));
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ... and extract the register number ... */
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int eregOfRM ( UChar mod_reg_rm )
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (Int)(mod_reg_rm & 0x7);
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get a 8/16/32-bit unsigned value out of the insn stream. */
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar getUChar ( Int delta )
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar v = guest_code[delta+0];
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toUChar(v);
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt getUDisp16 ( Int delta )
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt v = guest_code[delta+1]; v <<= 8;
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+0];
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return v & 0xFFFF;
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt getUDisp32 ( Int delta )
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt v = guest_code[delta+3]; v <<= 8;
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+2]; v <<= 8;
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+1]; v <<= 8;
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+0];
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return v;
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt getUDisp ( Int size, Int delta )
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (size) {
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return getUDisp32(delta);
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return getUDisp16(delta);
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return (UInt)getUChar(delta);
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("getUDisp(x86)");
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0; /*notreached*/
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get a byte value out of the insn stream and sign-extend to 32
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bits. */
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt getSDisp8 ( Int delta )
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return extend_s_8to32( (UInt) (guest_code[delta]) );
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt getSDisp16 ( Int delta0 )
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar* eip = (UChar*)(&guest_code[delta0]);
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt d = *eip++;
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   d |= ((*eip++) << 8);
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return extend_s_16to32(d);
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt getSDisp ( Int size, Int delta )
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (size) {
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return getUDisp32(delta);
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return getSDisp16(delta);
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return getSDisp8(delta);
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("getSDisp(x86)");
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return 0; /*notreached*/
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helpers for constructing IR.                         ---*/
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Create a 1/2/4 byte read of an x86 integer registers.  For 16/8 bit
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register references, we need to take the host endianness into
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   account.  Supplied value is 0 .. 7 and in the Intel instruction
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   encoding. */
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRType szToITy ( Int n )
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (n) {
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return Ity_I8;
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return Ity_I16;
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return Ity_I32;
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("szToITy(x86)");
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* On a little-endian host, less significant bits of the guest
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   registers are at lower addresses.  Therefore, if a reference to a
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register low half has the safe guest state offset as a reference to
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the full register.
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int integerGuestRegOffset ( Int sz, UInt archreg )
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg < 8);
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Correct for little-endian host only. */
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 || sz == 2 || (sz == 1 && archreg < 4)) {
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (archreg) {
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_EAX: return OFFB_EAX;
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_EBX: return OFFB_EBX;
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_ECX: return OFFB_ECX;
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_EDX: return OFFB_EDX;
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_ESI: return OFFB_ESI;
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_EDI: return OFFB_EDI;
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_ESP: return OFFB_ESP;
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_EBP: return OFFB_EBP;
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vpanic("integerGuestRegOffset(x86,le)(4,2)");
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg >= 4 && archreg < 8 && sz == 1);
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (archreg-4) {
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_EAX: return 1+ OFFB_EAX;
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_EBX: return 1+ OFFB_EBX;
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_ECX: return 1+ OFFB_ECX;
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_EDX: return 1+ OFFB_EDX;
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("integerGuestRegOffset(x86,le)(1h)");
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* NOTREACHED */
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("integerGuestRegOffset(x86,le)");
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int segmentGuestRegOffset ( UInt sreg )
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sreg) {
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_ES: return OFFB_ES;
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_CS: return OFFB_CS;
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_SS: return OFFB_SS;
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_DS: return OFFB_DS;
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_FS: return OFFB_FS;
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_GS: return OFFB_GS;
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("segmentGuestRegOffset(x86)");
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int xmmGuestRegOffset ( UInt xmmreg )
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (xmmreg) {
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: return OFFB_XMM0;
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return OFFB_XMM1;
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return OFFB_XMM2;
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: return OFFB_XMM3;
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return OFFB_XMM4;
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5: return OFFB_XMM5;
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: return OFFB_XMM6;
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7: return OFFB_XMM7;
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("xmmGuestRegOffset");
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lanes of vector registers are always numbered from zero being the
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   least significant lane (rightmost in the register).  */
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Correct for little-endian host only. */
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(laneno >= 0 && laneno < 8);
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Correct for little-endian host only. */
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(laneno >= 0 && laneno < 4);
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Correct for little-endian host only. */
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(laneno >= 0 && laneno < 2);
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getIReg ( Int sz, UInt archreg )
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 1 || sz == 2 || sz == 4);
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg < 8);
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( integerGuestRegOffset(sz,archreg),
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      szToITy(sz) );
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Ditto, but write to a reg instead. */
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putIReg ( Int sz, UInt archreg, IRExpr* e )
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = typeOfIRExpr(irsb->tyenv, e);
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: vassert(ty == Ity_I8); break;
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: vassert(ty == Ity_I16); break;
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: vassert(ty == Ity_I32); break;
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("putIReg(x86)");
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg < 8);
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getSReg ( UInt sreg )
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putSReg ( UInt sreg, IRExpr* e )
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMReg ( UInt xmmreg )
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMReg ( UInt xmmreg, IRExpr* e )
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_V128);
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F64);
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F32);
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void assign ( IRTemp dst, IRExpr* e )
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_WrTmp(dst, e) );
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void storeLE ( IRExpr* addr, IRExpr* data )
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Store(Iend_LE, addr, data) );
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* unop ( IROp op, IRExpr* a )
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Unop(op, a);
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Binop(op, a1, a2);
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Triop(op, a1, a2, a3);
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkexpr ( IRTemp tmp )
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_RdTmp(tmp);
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU8 ( UInt i )
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(i < 256);
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U8( (UChar)i ));
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU16 ( UInt i )
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(i < 65536);
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U16( (UShort)i ));
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU32 ( UInt i )
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U32(i));
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU64 ( ULong i )
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U64(i));
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU ( IRType ty, UInt i )
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ty == Ity_I8)  return mkU8(i);
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ty == Ity_I16) return mkU16(i);
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ty == Ity_I32) return mkU32(i);
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If this panics, it usually means you passed a size (1,2,4)
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      value as the IRType, rather than a real IRType. */
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("mkU(x86)");
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkV128 ( UShort mask )
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_V128(mask));
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* loadLE ( IRType ty, IRExpr* addr )
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Load(Iend_LE, ty, addr);
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IROp mkSizedOp ( IRType ty, IROp op8 )
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int adj;
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_Mul8
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_CasCmpNE8
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_Not8);
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return adj + op8;
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szSmall == 1 && szBig == 4) {
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return signd ? Iop_8Sto32 : Iop_8Uto32;
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szSmall == 1 && szBig == 2) {
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return signd ? Iop_8Sto16 : Iop_8Uto16;
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szSmall == 2 && szBig == 4) {
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return signd ? Iop_16Sto32 : Iop_16Uto32;
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("mkWidenOp(x86,guest)");
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkAnd1 ( IRExpr* x, IRExpr* y )
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,x) == Ity_I1);
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,y) == Ity_I1);
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return unop(Iop_32to1,
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_And32,
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto32,x),
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto32,y)));
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate a compare-and-swap operation, operating on memory at
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'addr'.  The expected value is 'expVal' and the new value is
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'newVal'.  If the operation fails, then transfer control (with a
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   no-redir jump (XXX no -- see comment at top of this file)) to
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'restart_point', which is presumably the address of the guest
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction again -- retrying, essentially. */
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void casLE ( IRExpr* addr, IRExpr* expVal, IRExpr* newVal,
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Addr32 restart_point )
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRCAS* cas;
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType tyE    = typeOfIRExpr(irsb->tyenv, expVal);
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType tyN    = typeOfIRExpr(irsb->tyenv, newVal);
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp oldTmp = newTemp(tyE);
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp expTmp = newTemp(tyE);
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(tyE == tyN);
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(tyE == Ity_I32 || tyE == Ity_I16 || tyE == Ity_I8);
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(expTmp, expVal);
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cas = mkIRCAS( IRTemp_INVALID, oldTmp, Iend_LE, addr,
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  NULL, mkexpr(expTmp), NULL, newVal );
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_CAS(cas) );
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Exit(
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( mkSizedOp(tyE,Iop_CasCmpNE8),
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mkexpr(oldTmp), mkexpr(expTmp) ),
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Ijk_Boring, /*Ijk_NoRedir*/
771663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            IRConst_U32( restart_point ),
772663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            OFFB_EIP
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helpers for %eflags.                                 ---*/
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Evaluating the flags-thunk. -------------- */
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate all the eflags from stored
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression ::
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ity_I32. */
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_x86g_calculate_eflags_all ( void )
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* call
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprCCall(
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Ity_I32,
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           0/*regparm*/,
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           "x86g_calculate_eflags_all", &x86g_calculate_eflags_all,
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           args
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Exclude OP and NDEP from definedness checking.  We're only
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      interested in DEP1 and DEP2. */
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return call;
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate some particular condition from stored
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression ::
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ity_Bit. */
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_x86g_calculate_condition ( X86Condcode cond )
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprVec_5( mkU32(cond),
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_OP,  Ity_I32),
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* call
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprCCall(
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Ity_I32,
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           0/*regparm*/,
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           "x86g_calculate_condition", &x86g_calculate_condition,
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           args
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Exclude the requested condition, OP and NDEP from definedness
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      checking.  We're only interested in DEP1 and DEP2. */
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return unop(Iop_32to1, call);
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate just the carry flag from stored
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression :: Ity_I32. */
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_x86g_calculate_eflags_c ( void )
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* call
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprCCall(
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Ity_I32,
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           3/*regparm*/,
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           "x86g_calculate_eflags_c", &x86g_calculate_eflags_c,
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           args
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Exclude OP and NDEP from definedness checking.  We're only
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      interested in DEP1 and DEP2. */
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return call;
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Building the flags-thunk. -------------- */
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The machinery in this section builds the flag-thunk following a
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   flag-setting operation.  Hence the various setFlags_* functions.
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool isAddSub ( IROp op8 )
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool isLogic ( IROp op8 )
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* U-widen 8/16/32 bit int expr to 32. */
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* widenUto32 ( IRExpr* e )
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (typeOfIRExpr(irsb->tyenv,e)) {
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: return e;
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: return unop(Iop_16Uto32,e);
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:  return unop(Iop_8Uto32,e);
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("widenUto32");
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* S-widen 8/16/32 bit int expr to 32. */
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* widenSto32 ( IRExpr* e )
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (typeOfIRExpr(irsb->tyenv,e)) {
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: return e;
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: return unop(Iop_16Sto32,e);
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:  return unop(Iop_8Sto32,e);
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("widenSto32");
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Narrow 8/16/32 bit int expr to 8/16/32.  Clearly only some
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of these combinations make sense. */
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType src_ty = typeOfIRExpr(irsb->tyenv,e);
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (src_ty == dst_ty)
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return e;
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (src_ty == Ity_I32 && dst_ty == Ity_I16)
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_32to16, e);
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (src_ty == Ity_I32 && dst_ty == Ity_I8)
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_32to8, e);
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf("\nsrc, dst tys are: ");
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ppIRType(src_ty);
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf(", ");
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ppIRType(dst_ty);
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf("\n");
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("narrowTo(x86)");
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Set the flags thunk OP, DEP1 and DEP2 fields.  The supplied op is
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   auto-sized up to the real op. */
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op8) {
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Add8: ccOp += X86G_CC_OP_ADDB;   break;
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Sub8: ccOp += X86G_CC_OP_SUBB;   break;
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:       ppIROp(op8);
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vpanic("setFlags_DEP1_DEP2(x86)");
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(ccOp)) );
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Set the OP and DEP1 fields only, and write zero to DEP2. */
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op8) {
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Or8:
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_And8:
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Xor8: ccOp += X86G_CC_OP_LOGICB; break;
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:       ppIROp(op8);
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vpanic("setFlags_DEP1(x86)");
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(ccOp)) );
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For shift operations, we put in the result and the undershifted
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   result.  Except if the shift amount is zero, the thunk is left
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unchanged. */
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void setFlags_DEP1_DEP2_shift ( IROp    op32,
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       IRTemp  res,
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       IRTemp  resUS,
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       IRType  ty,
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       IRTemp  guard )
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guard);
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Both kinds of right shifts are handled by the same thunk
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      operation. */
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op32) {
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shr32:
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Sar32: ccOp = X86G_CC_OP_SHRL - ccOp; break;
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shl32: ccOp = X86G_CC_OP_SHLL - ccOp; break;
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:        ppIROp(op32);
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      vpanic("setFlags_DEP1_DEP2_shift(x86)");
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* DEP1 contains the result, DEP2 contains the undershifted value. */
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRExpr_Mux0X( mkexpr(guard),
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   IRExpr_Get(OFFB_CC_OP,Ity_I32),
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU32(ccOp))) );
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1,
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRExpr_Mux0X( mkexpr(guard),
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   widenUto32(mkexpr(res)))) );
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2,
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRExpr_Mux0X( mkexpr(guard),
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   widenUto32(mkexpr(resUS)))) );
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
1002b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   stmt( IRStmt_Put( OFFB_CC_NDEP,
1003b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     IRExpr_Mux0X( mkexpr(guard),
1004b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                   IRExpr_Get(OFFB_CC_NDEP,Ity_I32),
1005b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov				   mkU32(0) )));
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For the inc/dec case, we store in DEP1 the result value and in NDEP
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the former value of the carry flag, which unfortunately we have to
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   compute. */
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int ccOp = inc ? X86G_CC_OP_INCB : X86G_CC_OP_DECB;
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This has to come first, because calculating the C flag
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      may require reading all four thunk fields. */
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mk_x86g_calculate_eflags_c()) );
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(ccOp)) );
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(res))) );
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   two arguments. */
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (ty) {
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16:
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32:
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("setFlags_MUL(x86)");
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Condition codes. -------------- */
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Condition codes, using the Intel encoding.  */
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* name_X86Condcode ( X86Condcode cond )
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (cond) {
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondO:      return "o";
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNO:     return "no";
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondB:      return "b";
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNB:     return "nb";
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondZ:      return "z";
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNZ:     return "nz";
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondBE:     return "be";
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNBE:    return "nbe";
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondS:      return "s";
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNS:     return "ns";
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondP:      return "p";
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNP:     return "np";
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondL:      return "l";
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNL:     return "nl";
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondLE:     return "le";
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNLE:    return "nle";
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondAlways: return "ALWAYS";
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("name_X86Condcode");
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownX86Condcode positiveIse_X86Condcode ( X86Condcode  cond,
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      Bool*        needInvert )
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(cond >= X86CondO && cond <= X86CondNLE);
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cond & 1) {
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *needInvert = True;
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return cond-1;
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *needInvert = False;
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return cond;
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Helpers for ADD/SUB with carry. -------------- */
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   appropriately.
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Optionally, generate a store for the 'tres' value.  This can either
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   be a normal store, or it can be a cas-with-possible-failure style
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   store:
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if taddr is IRTemp_INVALID, then no store is generated.
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if taddr is not IRTemp_INVALID, then a store (using taddr as
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the address) is generated:
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if texpVal is IRTemp_INVALID then a normal store is
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     generated, and restart_point must be zero (it is irrelevant).
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if texpVal is not IRTemp_INVALID then a cas-style store is
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     generated.  texpVal is the expected value, restart_point
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     is the restart point if the store fails, and texpVal must
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     have the same type as tres.
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void helper_ADC ( Int sz,
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp tres, IRTemp ta1, IRTemp ta2,
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /* info about optional store: */
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt    thunkOp;
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty    = szToITy(sz);
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldc  = newTemp(Ity_I32);
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldcn = newTemp(ty);
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    plus  = mkSizedOp(ty, Iop_Add8);
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    xor   = mkSizedOp(ty, Iop_Xor8);
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 1 || sz == 2 || sz == 4);
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thunkOp = sz==4 ? X86G_CC_OP_ADCL
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   : (sz==2 ? X86G_CC_OP_ADCW : X86G_CC_OP_ADCB);
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* oldc = old carry flag, 0 or 1 */
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldc,  binop(Iop_And32,
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mk_x86g_calculate_eflags_c(),
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32(1)) );
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tres, binop(plus,
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(plus,mkexpr(ta1),mkexpr(ta2)),
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(oldcn)) );
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Possibly generate a store of 'tres' to 'taddr'.  See comment at
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      start of this function. */
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (taddr != IRTemp_INVALID) {
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (texpVal == IRTemp_INVALID) {
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(restart_point == 0);
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(taddr), mkexpr(tres) );
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* .. and hence 'texpVal' has the same type as 'tres'. */
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         casLE( mkexpr(taddr),
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mkexpr(texpVal), mkexpr(tres), restart_point );
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(thunkOp) ) );
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1)) ));
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                         mkexpr(oldcn)) )) );
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   appropriately.  As with helper_ADC, possibly generate a store of
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the result -- see comments on helper_ADC for details.
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void helper_SBB ( Int sz,
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp tres, IRTemp ta1, IRTemp ta2,
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /* info about optional store: */
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt    thunkOp;
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty    = szToITy(sz);
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldc  = newTemp(Ity_I32);
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldcn = newTemp(ty);
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    minus = mkSizedOp(ty, Iop_Sub8);
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    xor   = mkSizedOp(ty, Iop_Xor8);
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 1 || sz == 2 || sz == 4);
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thunkOp = sz==4 ? X86G_CC_OP_SBBL
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   : (sz==2 ? X86G_CC_OP_SBBW : X86G_CC_OP_SBBB);
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* oldc = old carry flag, 0 or 1 */
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldc, binop(Iop_And32,
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mk_x86g_calculate_eflags_c(),
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(1)) );
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tres, binop(minus,
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(minus,mkexpr(ta1),mkexpr(ta2)),
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(oldcn)) );
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Possibly generate a store of 'tres' to 'taddr'.  See comment at
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      start of this function. */
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (taddr != IRTemp_INVALID) {
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (texpVal == IRTemp_INVALID) {
1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(restart_point == 0);
1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(taddr), mkexpr(tres) );
1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* .. and hence 'texpVal' has the same type as 'tres'. */
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         casLE( mkexpr(taddr),
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mkexpr(texpVal), mkexpr(tres), restart_point );
1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(thunkOp) ) );
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1) )) );
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                         mkexpr(oldcn)) )) );
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Helpers for disassembly printing. -------------- */
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameGrp1 ( Int opc_aux )
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* grp1_names[8]
1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp1_names[opc_aux];
1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameGrp2 ( Int opc_aux )
1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* grp2_names[8]
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp2_names[opc_aux];
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameGrp4 ( Int opc_aux )
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* grp4_names[8]
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp4_names[opc_aux];
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameGrp5 ( Int opc_aux )
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* grp5_names[8]
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp5_names[opc_aux];
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameGrp8 ( Int opc_aux )
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* grp8_names[8]
1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(x86)");
1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp8_names[opc_aux];
1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameIReg ( Int size, Int reg )
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* ireg32_names[8]
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%eax", "%ecx", "%edx", "%ebx",
1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%esp", "%ebp", "%esi", "%edi" };
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* ireg16_names[8]
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* ireg8_names[8]
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%al", "%cl", "%dl", "%bl",
1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (reg < 0 || reg > 7) goto bad;
1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (size) {
1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return ireg32_names[reg];
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return ireg16_names[reg];
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return ireg8_names[reg];
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  bad:
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("nameIReg(X86)");
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return NULL; /*notreached*/
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameSReg ( UInt sreg )
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sreg) {
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_ES: return "%es";
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_CS: return "%cs";
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_SS: return "%ss";
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_DS: return "%ds";
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_FS: return "%fs";
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_GS: return "%gs";
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameSReg(x86)");
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameMMXReg ( Int mmxreg )
1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* mmx_names[8]
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return mmx_names[mmxreg];
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameXMMReg ( Int xmmreg )
1310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* xmm_names[8]
1312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (xmmreg < 0 || xmmreg > 7) vpanic("name_of_xmm_reg");
1315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xmm_names[xmmreg];
1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameMMXGran ( Int gran )
1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gran) {
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: return "b";
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return "w";
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return "d";
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: return "q";
1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameMMXGran(x86,guest)");
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar nameISize ( Int size )
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (size) {
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return 'l';
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return 'w';
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return 'b';
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameISize(x86)");
1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- JMP helpers                                          ---*/
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1344663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengstatic void jmp_lit( /*MOD*/DisResult* dres,
1345663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     IRJumpKind kind, Addr32 d32 )
1346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1347663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->whatNext    == Dis_Continue);
1348663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->len         == 0);
1349663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->continueAt  == 0);
1350663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->jk_StopHere == Ijk_INVALID);
1351663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres->whatNext    = Dis_StopHere;
1352663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres->jk_StopHere = kind;
1353663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   stmt( IRStmt_Put( OFFB_EIP, mkU32(d32) ) );
1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1356663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengstatic void jmp_treg( /*MOD*/DisResult* dres,
1357663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                      IRJumpKind kind, IRTemp t )
1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1359663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->whatNext    == Dis_Continue);
1360663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->len         == 0);
1361663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->continueAt  == 0);
1362663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->jk_StopHere == Ijk_INVALID);
1363663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres->whatNext    = Dis_StopHere;
1364663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres->jk_StopHere = kind;
1365663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   stmt( IRStmt_Put( OFFB_EIP, mkexpr(t) ) );
1366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1369663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengvoid jcc_01( /*MOD*/DisResult* dres,
1370663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng             X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
1371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool        invert;
1373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   X86Condcode condPos;
1374663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->whatNext    == Dis_Continue);
1375663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->len         == 0);
1376663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->continueAt  == 0);
1377663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->jk_StopHere == Ijk_INVALID);
1378663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres->whatNext    = Dis_StopHere;
1379663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres->jk_StopHere = Ijk_Boring;
1380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   condPos = positiveIse_X86Condcode ( cond, &invert );
1381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (invert) {
1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Ijk_Boring,
1384663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         IRConst_U32(d32_false),
1385663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         OFFB_EIP ) );
1386663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      stmt( IRStmt_Put( OFFB_EIP, mkU32(d32_true) ) );
1387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
1389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Ijk_Boring,
1390663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         IRConst_U32(d32_true),
1391663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         OFFB_EIP ) );
1392663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      stmt( IRStmt_Put( OFFB_EIP, mkU32(d32_false) ) );
1393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassembling addressing modes                       ---*/
1399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownHChar* sorbTxt ( UChar sorb )
1403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sorb) {
1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0:    return ""; /* no override */
1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x3E: return "%ds";
1407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x26: return "%es:";
1408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x64: return "%fs:";
1409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x65: return "%gs:";
1410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("sorbTxt(x86,guest)");
1411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 'virtual' is an IRExpr* holding a virtual address.  Convert it to a
1416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   linear address by adding any required segment override as indicated
1417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   by sorb. */
1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    sreg;
1422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType hWordTy;
1423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sorb == 0)
1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* the common case - no override */
1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return virtual;
1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sorb) {
1430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x3E: sreg = R_DS; break;
1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x26: sreg = R_ES; break;
1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x64: sreg = R_FS; break;
1433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x65: sreg = R_GS; break;
1434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("handleSegOverride(x86,guest)");
1435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   seg_selector = newTemp(Ity_I32);
1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ldt_ptr      = newTemp(hWordTy);
1441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gdt_ptr      = newTemp(hWordTy);
1442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r64          = newTemp(Ity_I64);
1443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
1445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*
1449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Call this to do the translation and limit checks:
1450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
1451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 UInt seg_selector, UInt virtual_addr )
1452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      r64,
1455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mkIRExprCCall(
1456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Ity_I64,
1457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         0/*regparms*/,
1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "x86g_use_seg_selector",
1459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         &x86g_use_seg_selector,
1460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
1461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(seg_selector), virtual)
1462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If the high 32 of the result are non-zero, there was a
1466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      failure in address translation.  In which case, make a
1467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      quick exit.
1468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt(
1470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Exit(
1471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
1472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Ijk_MapFail,
1473663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         IRConst_U32( guest_EIP_curr_instr ),
1474663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         OFFB_EIP
1475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* otherwise, here's the translated result. */
1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return unop(Iop_64to32, mkexpr(r64));
1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate IR to calculate an address indicated by a ModRM and
1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   following SIB bytes.  The expression, and the number of bytes in
1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the address mode, are returned.  Note that this fn should not be
1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   called if the R/M part of the address denotes a register instead of
1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memory.  If print_codegen is true, text of the addressing mode is
1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   placed in buf.
1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The computed address is stored in a new tempreg, and the
1491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   identity of the tempreg is returned.  */
1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmp = newTemp(Ity_I32);
1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tmp, addr32 );
1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return tmp;
1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRTemp disAMode ( Int* len, UChar sorb, Int delta, HChar* buf )
1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar mod_reg_rm = getIByte(delta);
1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta++;
1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf[0] = (UChar)0;
1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jump table seems a bit excessive.
1510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm &= 0xC7;                      /* is now XX000YYY */
1512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm  = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            /* is now XX0XXYYY */
1514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm &= 0x1F;                      /* is now 000XXYYY */
1515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (mod_reg_rm) {
1516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         --> GET %reg, t
1519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x00: case 0x01: case 0x02: case 0x03:
1521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         { UChar rm = mod_reg_rm;
1523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *len = 1;
1525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           return disAMode_copy2tmp(
1526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  handleSegOverride(sorb, getIReg(4,rm)));
1527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* d8(%eax) ... d8(%edi), not including d8(%esp)
1530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         --> GET %reg, t ; ADDL d8, t
1531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x08: case 0x09: case 0x0A: case 0x0B:
1533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         { UChar rm = toUChar(mod_reg_rm & 7);
1535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           UInt  d  = getSDisp8(delta);
1536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIS(buf, "%s%d(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
1537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *len = 2;
1538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           return disAMode_copy2tmp(
1539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  handleSegOverride(sorb,
1540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
1541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* d32(%eax) ... d32(%edi), not including d32(%esp)
1544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         --> GET %reg, t ; ADDL d8, t
1545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x10: case 0x11: case 0x12: case 0x13:
1547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 14 */ case 0x15: case 0x16: case 0x17:
1548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         { UChar rm = toUChar(mod_reg_rm & 7);
1549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           UInt  d  = getUDisp32(delta);
1550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
1551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *len = 5;
1552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           return disAMode_copy2tmp(
1553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  handleSegOverride(sorb,
1554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
1555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* a register, %eax .. %edi.  This shouldn't happen. */
1558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x18: case 0x19: case 0x1A: case 0x1B:
1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("disAMode(x86): not an addr!");
1561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* a 32-bit literal address
1563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         --> MOV d32, tmp
1564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x05:
1566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         { UInt d = getUDisp32(delta);
1567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *len = 5;
1568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
1569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           return disAMode_copy2tmp(
1570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     handleSegOverride(sorb, mkU32(d)));
1571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x04: {
1574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* SIB, with no displacement.  Special cases:
1575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            -- %esp cannot act as an index value.
1576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               If index_r indicates %esp, zero is used for the index.
1577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            -- when mod is zero and base indicates EBP, base is instead
1578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               a 32-bit literal.
1579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            It's all madness, I tell you.  Extract %index, %base and
1580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            scale from the SIB byte.  The value denoted is then:
1581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               | %index == %ESP && %base == %EBP
1582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               = d32 following SIB byte
1583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               | %index == %ESP && %base != %EBP
1584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               = %base
1585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               | %index != %ESP && %base == %EBP
1586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               = d32 following SIB byte + (%index << scale)
1587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               | %index != %ESP && %base != %ESP
1588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               = %base + (%index << scale)
1589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            What happens to the souls of CPU architects who dream up such
1591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            horrendous schemes, do you suppose?
1592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
1593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar sib     = getIByte(delta);
1594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar scale   = toUChar((sib >> 6) & 3);
1595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar index_r = toUChar((sib >> 3) & 7);
1596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar base_r  = toUChar(sib & 7);
1597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
1598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r != R_ESP && base_r != R_EBP) {
1600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 2;
1603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return
1604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               disAMode_copy2tmp(
1605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               handleSegOverride(sorb,
1606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Add32,
1607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getIReg(4,base_r),
1608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl32, getIReg(4,index_r),
1609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(scale)))));
1610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r != R_ESP && base_r == R_EBP) {
1613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UInt d = getUDisp32(delta);
1614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameIReg(4,index_r), 1<<scale);
1616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 6;
1617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return
1618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               disAMode_copy2tmp(
1619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               handleSegOverride(sorb,
1620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Add32,
1621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
1622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32(d))));
1623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r == R_ESP && base_r != R_EBP) {
1626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
1627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 2;
1628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return disAMode_copy2tmp(
1629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   handleSegOverride(sorb, getIReg(4,base_r)));
1630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r == R_ESP && base_r == R_EBP) {
1633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UInt d = getUDisp32(delta);
1634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s0x%x(,,)", sorbTxt(sorb), d);
1635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 6;
1636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return disAMode_copy2tmp(
1637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   handleSegOverride(sorb, mkU32(d)));
1638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
1640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
1641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, with 8-bit displacement.  Special cases:
1644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         -- %esp cannot act as an index value.
1645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            If index_r indicates %esp, zero is used for the index.
1646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Denoted value is:
1647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            | %index == %ESP
1648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = d8 + %base
1649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            | %index != %ESP
1650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = d8 + %base + (%index << scale)
1651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x0C: {
1653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar sib     = getIByte(delta);
1654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar scale   = toUChar((sib >> 6) & 3);
1655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar index_r = toUChar((sib >> 3) & 7);
1656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar base_r  = toUChar(sib & 7);
1657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt  d       = getSDisp8(delta+1);
1658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r == R_ESP) {
1660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   (Int)d, nameIReg(4,base_r));
1662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 3;
1663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return disAMode_copy2tmp(
1664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   handleSegOverride(sorb,
1665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
1666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
1667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 3;
1670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return
1671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                disAMode_copy2tmp(
1672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                handleSegOverride(sorb,
1673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Add32,
1674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Add32,
1675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              getIReg(4,base_r),
1676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl32,
1677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    getIReg(4,index_r), mkU8(scale))),
1678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32(d))));
1679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /*NOTREACHED*/
1681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
1682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, with 32-bit displacement.  Special cases:
1685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         -- %esp cannot act as an index value.
1686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            If index_r indicates %esp, zero is used for the index.
1687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Denoted value is:
1688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            | %index == %ESP
1689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = d32 + %base
1690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            | %index != %ESP
1691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = d32 + %base + (%index << scale)
1692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x14: {
1694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar sib     = getIByte(delta);
1695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar scale   = toUChar((sib >> 6) & 3);
1696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar index_r = toUChar((sib >> 3) & 7);
1697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar base_r  = toUChar(sib & 7);
1698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt d        = getUDisp32(delta+1);
1699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r == R_ESP) {
1701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   (Int)d, nameIReg(4,base_r));
1703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 6;
1704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return disAMode_copy2tmp(
1705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   handleSegOverride(sorb,
1706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
1707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
1708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 6;
1711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return
1712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                disAMode_copy2tmp(
1713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                handleSegOverride(sorb,
1714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Add32,
1715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Add32,
1716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              getIReg(4,base_r),
1717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl32,
1718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    getIReg(4,index_r), mkU8(scale))),
1719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32(d))));
1720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /*NOTREACHED*/
1722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
1723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
1726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("disAMode(x86)");
1727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 0; /*notreached*/
1728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Figure out the number of (insn-stream) bytes constituting the amode
1733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   beginning at delta.  Is useful for getting hold of literals beyond
1734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the end of the amode before it has been disassembled.  */
1735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt lengthAMode ( Int delta )
1737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar mod_reg_rm = getIByte(delta); delta++;
1739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jump table seems a bit excessive.
1742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm &= 0xC7;               /* is now XX000YYY */
1744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm  = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     /* is now XX0XXYYY */
1746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm &= 0x1F;               /* is now 000XXYYY */
1747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (mod_reg_rm) {
1748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x00: case 0x01: case 0x02: case 0x03:
1751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 1;
1753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x08: case 0x09: case 0x0A: case 0x0B:
1756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 2;
1758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x10: case 0x11: case 0x12: case 0x13:
1761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 14 */ case 0x15: case 0x16: case 0x17:
1762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 5;
1763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* a register, %eax .. %edi.  (Not an addr, but still handled.) */
1765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x18: case 0x19: case 0x1A: case 0x1B:
1766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 1;
1768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* a 32-bit literal address. */
1770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x05: return 5;
1771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, no displacement.  */
1773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x04: {
1774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar sib    = getIByte(delta);
1775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar base_r = toUChar(sib & 7);
1776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (base_r == R_EBP) return 6; else return 2;
1777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, with 8-bit displacement.  */
1779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x0C: return 3;
1780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, with 32-bit displacement.  */
1782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x14: return 6;
1783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
1785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("lengthAMode");
1786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 0; /*notreached*/
1787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassembling common idioms                          ---*/
1792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle binary integer instructions of the form
1795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op E, G  meaning
1796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op reg-or-mem, reg
1797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Is passed the a ptr to the modRM byte, the actual operation, and the
1798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   data size.  Returns the address advanced completely over this
1799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction.
1800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(src) is reg-or-mem
1802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(dst) is reg.
1803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %G,  tmp
1805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP %E,   tmp
1806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmp, %G
1807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem and OP is not reversible,
1809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                -->    (getAddr E) -> tmpa
1810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmpa
1811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       GET %G, tmp2
1812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP tmpa, tmp2
1813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmp2, %G
1814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem and OP is reversible
1816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                -->    (getAddr E) -> tmpa
1817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmpa
1818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP %G, tmpa
1819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpa, %G
1820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_op2_E_G ( UChar       sorb,
1823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Bool        addSubCarry,
1824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   IROp        op8,
1825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Bool        keep,
1826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         size,
1827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         delta0,
1828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   HChar*      t_x86opc )
1829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
1831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
1832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty   = szToITy(size);
1833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst1 = newTemp(ty);
1834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  src  = newTemp(ty);
1835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst0 = newTemp(ty);
1836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getUChar(delta0);
1837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr = IRTemp_INVALID;
1838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* addSubCarry == True indicates the intended operation is
1840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add-with-carry or subtract-with-borrow. */
1841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (addSubCarry) {
1842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(keep);
1844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
1847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Specially handle XOR reg,reg, because that doesn't really
1848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         depend on reg, and doing the obvious thing potentially
1849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         generates a spurious value check failure due to the bogus
1850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dependency.  Ditto SBB reg,reg. */
1851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && gregOfRM(rm) == eregOfRM(rm)) {
1853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, gregOfRM(rm), mkU(ty,0));
1854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst0, getIReg(size,gregOfRM(rm)) );
1856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src,  getIReg(size,eregOfRM(rm)) );
1857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Add8) {
1859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_ADC( size, dst1, dst0, src,
1860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
1863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Sub8) {
1864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_SBB( size, dst1, dst0, src,
1865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
1869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
1870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
1871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
1872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
1873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (keep)
1874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(size, gregOfRM(rm), mkexpr(dst1));
1875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIReg(size,eregOfRM(rm)),
1879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIReg(size,gregOfRM(rm)));
1880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
1881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* E refers to memory */
1883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta0, dis_buf);
1884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst0, getIReg(size,gregOfRM(rm)) );
1885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src,  loadLE(szToITy(size), mkexpr(addr)) );
1886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Add8) {
1888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_ADC( size, dst1, dst0, src,
1889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
1892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Sub8) {
1893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_SBB( size, dst1, dst0, src,
1894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
1898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
1899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
1900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
1901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
1902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (keep)
1903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(size, gregOfRM(rm), mkexpr(dst1));
1904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          dis_buf,nameIReg(size,gregOfRM(rm)));
1908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
1909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle binary integer instructions of the form
1915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op G, E  meaning
1916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op reg, reg-or-mem
1917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Is passed the a ptr to the modRM byte, the actual operation, and the
1918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   data size.  Returns the address advanced completely over this
1919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction.
1920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(src) is reg.
1922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(dst) is reg-or-mem
1923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %E,  tmp
1925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP %G,   tmp
1926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmp, %E
1927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem, -->    (getAddr E) -> tmpa
1929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmpv
1930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP %G, tmpv
1931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       ST tmpv, (tmpa)
1932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_op2_G_E ( UChar       sorb,
1935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Bool        locked,
1936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Bool        addSubCarry,
1937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   IROp        op8,
1938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Bool        keep,
1939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         size,
1940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         delta0,
1941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   HChar*      t_x86opc )
1942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
1944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
1945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty   = szToITy(size);
1946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst1 = newTemp(ty);
1947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  src  = newTemp(ty);
1948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst0 = newTemp(ty);
1949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getIByte(delta0);
1950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr = IRTemp_INVALID;
1951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* addSubCarry == True indicates the intended operation is
1953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add-with-carry or subtract-with-borrow. */
1954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (addSubCarry) {
1955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(keep);
1957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
1960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Specially handle XOR reg,reg, because that doesn't really
1961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         depend on reg, and doing the obvious thing potentially
1962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         generates a spurious value check failure due to the bogus
1963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dependency.  Ditto SBB reg,reg.*/
1964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && gregOfRM(rm) == eregOfRM(rm)) {
1966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, eregOfRM(rm), mkU(ty,0));
1967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, getIReg(size,eregOfRM(rm)));
1969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src,  getIReg(size,gregOfRM(rm)));
1970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Add8) {
1972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_ADC( size, dst1, dst0, src,
1973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, eregOfRM(rm), mkexpr(dst1));
1975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
1976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Sub8) {
1977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_SBB( size, dst1, dst0, src,
1978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, eregOfRM(rm), mkexpr(dst1));
1980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
1982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
1983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
1984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
1985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
1986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (keep)
1987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(size, eregOfRM(rm), mkexpr(dst1));
1988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIReg(size,gregOfRM(rm)),
1992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIReg(size,eregOfRM(rm)));
1993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
1994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
1997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta0, dis_buf);
1999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, loadLE(ty,mkexpr(addr)));
2000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src,  getIReg(size,gregOfRM(rm)));
2001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Add8) {
2003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (locked) {
2004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* cas-style store */
2005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_ADC( size, dst1, dst0, src,
2006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* normal store */
2009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_ADC( size, dst1, dst0, src,
2010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, IRTemp_INVALID, 0 );
2011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
2013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Sub8) {
2014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (locked) {
2015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* cas-style store */
2016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_SBB( size, dst1, dst0, src,
2017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* normal store */
2020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_SBB( size, dst1, dst0, src,
2021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, IRTemp_INVALID, 0 );
2022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (keep) {
2026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
2027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0) vex_printf("locked case\n" );
2028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr),
2029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(dst0)/*expval*/,
2030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(dst1)/*newval*/, guest_EIP_curr_instr );
2031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
2032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0) vex_printf("nonlocked case\n");
2033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr), mkexpr(dst1));
2034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
2037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
2040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIReg(size,gregOfRM(rm)), dis_buf);
2044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
2045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle move instructions of the form
2050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mov E, G  meaning
2051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mov reg-or-mem, reg
2052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Is passed the a ptr to the modRM byte, and the data size.  Returns
2053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the address advanced completely over this instruction.
2054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(src) is reg-or-mem
2056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(dst) is reg.
2057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %E,  tmpv
2059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpv, %G
2060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem  -->    (getAddr E) -> tmpa
2062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmpb
2063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpb, %G
2064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_mov_E_G ( UChar       sorb,
2067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         size,
2068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         delta0 )
2069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int len;
2071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm = getIByte(delta0);
2072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
2073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
2075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
2076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s,%s\n", nameISize(size),
2077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg(size,eregOfRM(rm)),
2078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg(size,gregOfRM(rm)));
2079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
2080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
2083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
2084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
2085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
2086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s,%s\n", nameISize(size),
2087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           dis_buf,nameIReg(size,gregOfRM(rm)));
2088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta0+len;
2089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle move instructions of the form
2094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mov G, E  meaning
2095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mov reg, reg-or-mem
2096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Is passed the a ptr to the modRM byte, and the data size.  Returns
2097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the address advanced completely over this instruction.
2098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(src) is reg.
2100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(dst) is reg-or-mem
2101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %G,  tmp
2103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmp, %E
2104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem, -->    (getAddr E) -> tmpa
2106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       GET %G, tmpv
2107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       ST tmpv, (tmpa)
2108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_mov_G_E ( UChar       sorb,
2111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         size,
2112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         delta0 )
2113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int len;
2115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm = getIByte(delta0);
2116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
2117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
2119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
2120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s,%s\n", nameISize(size),
2121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg(size,gregOfRM(rm)),
2122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg(size,eregOfRM(rm)));
2123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
2124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
2127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
2128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
2129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
2130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s,%s\n", nameISize(size),
2131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg(size,gregOfRM(rm)), dis_buf);
2132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
2133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* op $immediate, AL/AX/EAX. */
2138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_op_imm_A ( Int    size,
2140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool   carrying,
2141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    IROp   op8,
2142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool   keep,
2143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int    delta,
2144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    HChar* t_x86opc )
2145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty   = szToITy(size);
2147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst0 = newTemp(ty);
2148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src  = newTemp(ty);
2149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst1 = newTemp(ty);
2150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt lit    = getUDisp(size,delta);
2151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(dst0, getIReg(size,R_EAX));
2152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(src,  mkU(ty,lit));
2153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isAddSub(op8) && !carrying) {
2155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2(op8, dst0, src, ty);
2157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isLogic(op8)) {
2160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!carrying);
2161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1(op8, dst1, ty);
2163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op8 == Iop_Add8 && carrying) {
2166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      helper_ADC( size, dst1, dst0, src,
2167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op8 == Iop_Sub8 && carrying) {
2171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      helper_SBB( size, dst1, dst0, src,
2172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vpanic("dis_op_imm_A(x86,guest)");
2176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (keep)
2178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, R_EAX, mkexpr(dst1));
2179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
2181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           lit, nameIReg(size,R_EAX));
2182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta+size;
2183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Sign- and Zero-extending moves. */
2187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_movx_E_G ( UChar      sorb,
2189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int delta, Int szs, Int szd, Bool sign_extend )
2190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm = getIByte(delta);
2192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
2193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (szd == szs) {
2194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // mutant case.  See #250799
2195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(szd, gregOfRM(rm),
2196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getIReg(szs,eregOfRM(rm)));
2197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // normal case
2199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(szd, gregOfRM(rm),
2200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      unop(mkWidenOp(szs,szd,sign_extend),
2201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getIReg(szs,eregOfRM(rm))));
2202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameISize(szs), nameISize(szd),
2205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(szs,eregOfRM(rm)),
2206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(szd,gregOfRM(rm)));
2207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta;
2208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
2211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
2212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    len;
2213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar  dis_buf[50];
2214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
2215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (szd == szs) {
2216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // mutant case.  See #250799
2217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(szd, gregOfRM(rm),
2218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           loadLE(szToITy(szs),mkexpr(addr)));
2219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // normal case
2221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(szd, gregOfRM(rm),
2222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      unop(mkWidenOp(szs,szd,sign_extend),
2223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           loadLE(szToITy(szs),mkexpr(addr))));
2224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameISize(szs), nameISize(szd),
2227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               dis_buf, nameIReg(szd,gregOfRM(rm)));
2228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta;
2229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
2234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   16 / 8 bit quantity in the given IRTemp.  */
2235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op    = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src64 = newTemp(Ity_I64);
2240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst64 = newTemp(Ity_I64);
2241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
2242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:
2243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src64, binop(Iop_32HLto64,
2244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              getIReg(4,R_EDX), getIReg(4,R_EAX)) );
2245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
2246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
2247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: {
2250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src64, unop(widen3264,
2253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_16HLto32,
2254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: {
2261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen816  = signed_divide ? Iop_8Sto16  : Iop_8Uto16;
2264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst64,
2266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, mkexpr(src64),
2267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(widen1632, unop(widen816, mkexpr(t)))) );
2268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(Iop_64to32,mkexpr(dst64)))) );
2270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(Iop_64HIto32,mkexpr(dst64)))) );
2272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("codegen_div(x86)");
2275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_Grp1 ( UChar sorb, Bool locked,
2281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Int delta, UChar modrm,
2282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Int am_sz, Int d_sz, Int sz, UInt d32 )
2283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
2285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
2286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty   = szToITy(sz);
2287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst1 = newTemp(ty);
2288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  src  = newTemp(ty);
2289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst0 = newTemp(ty);
2290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr = IRTemp_INVALID;
2291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    op8  = Iop_INVALID;
2292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt    mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
2293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregOfRM(modrm)) {
2295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: op8 = Iop_Add8; break;  case 1: op8 = Iop_Or8;  break;
2296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: break;  // ADC
2297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: break;  // SBB
2298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: op8 = Iop_And8; break;  case 5: op8 = Iop_Sub8; break;
2299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: op8 = Iop_Xor8; break;  case 7: op8 = Iop_Sub8; break;
2300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
2301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("dis_Grp1: unhandled case");
2302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
2305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(am_sz == 1);
2306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, getIReg(sz,eregOfRM(modrm)));
2308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src,  mkU(ty,d32 & mask));
2309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregOfRM(modrm) == 2 /* ADC */) {
2311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_ADC( sz, dst1, dst0, src,
2312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
2314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregOfRM(modrm) == 3 /* SBB */) {
2315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_SBB( sz, dst1, dst0, src,
2316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
2320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
2323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregOfRM(modrm) < 7)
2326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += (am_sz + d_sz);
2329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameIReg(sz,eregOfRM(modrm)));
2331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta, dis_buf);
2333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, loadLE(ty,mkexpr(addr)));
2335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src, mkU(ty,d32 & mask));
2336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregOfRM(modrm) == 2 /* ADC */) {
2338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (locked) {
2339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* cas-style store */
2340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_ADC( sz, dst1, dst0, src,
2341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* normal store */
2344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_ADC( sz, dst1, dst0, src,
2345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, IRTemp_INVALID, 0 );
2346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
2348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregOfRM(modrm) == 3 /* SBB */) {
2349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (locked) {
2350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* cas-style store */
2351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_SBB( sz, dst1, dst0, src,
2352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* normal store */
2355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_SBB( sz, dst1, dst0, src,
2356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, IRTemp_INVALID, 0 );
2357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregOfRM(modrm) < 7) {
2361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
2362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(dst0)/*expVal*/,
2363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkexpr(dst1)/*newVal*/,
2364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    guest_EIP_curr_instr );
2365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
2366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr), mkexpr(dst1));
2367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
2370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
2373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += (len+d_sz);
2376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              d32, dis_buf);
2378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
2380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 2 extended opcodes.  shift_expr must be an 8-bit typed
2384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   expression. */
2385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_Grp2 ( UChar sorb,
2388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Int delta, UChar modrm,
2389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
2390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                HChar* shift_expr_txt, Bool* decode_OK )
2391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* delta on entry points at the modrm byte. */
2393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
2394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    len;
2395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   isShift, isRotate, isRotateC;
2396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty    = szToITy(sz);
2397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst0  = newTemp(ty);
2398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst1  = newTemp(ty);
2399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp addr  = IRTemp_INVALID;
2400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True;
2402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 1 || sz == 2 || sz == 4);
2404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Put value to shift/rotate in dst0. */
2406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
2407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, getIReg(sz, eregOfRM(modrm)));
2408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += (am_sz + d_sz);
2409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta, dis_buf);
2411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, loadLE(ty,mkexpr(addr)));
2412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len + d_sz;
2413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   isShift = False;
2416b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   switch (gregOfRM(modrm)) { case 4: case 5: case 6: case 7: isShift = True; }
2417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   isRotate = False;
2419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   isRotateC = False;
2422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregOfRM(modrm)) { case 2: case 3: isRotateC = True; }
2423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!isShift && !isRotate && !isRotateC) {
2425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
2426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vpanic("dis_Grp2(Reg): unhandled case(x86)");
2427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isRotateC) {
2430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* call a helper; these insns are so ridiculous they do not
2431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         deserve better */
2432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool     left = toBool(gregOfRM(modrm) == 2);
2433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp   r64  = newTemp(Ity_I64);
2434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr** args
2435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          widenUto32(shift_expr),   /* rotate amount */
2437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          widenUto32(mk_x86g_calculate_eflags_all()),
2438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(sz) );
2439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( r64, mkIRExprCCall(
2440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64,
2441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      0/*regparm*/,
2442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      left ? "x86g_calculate_RCL" : "x86g_calculate_RCR",
2443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      left ? &x86g_calculate_RCL  : &x86g_calculate_RCR,
2444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      args
2445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )
2446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
2447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* new eflags in hi half r64; new value in lo half r64 */
2448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
2449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
2450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
2451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Set NDEP even though it isn't used.  This makes redundant-PUT
2453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         elimination of previous stores to this field work better. */
2454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
2455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isShift) {
2458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp pre32     = newTemp(Ity_I32);
2460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res32     = newTemp(Ity_I32);
2461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res32ss   = newTemp(Ity_I32);
2462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp shift_amt = newTemp(Ity_I8);
2463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   op32;
2464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
2466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: op32 = Iop_Shl32; break;
2467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 5: op32 = Iop_Shr32; break;
2468b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case 6: op32 = Iop_Shl32; break;
2469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 7: op32 = Iop_Sar32; break;
2470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
2471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vpanic("dis_Grp2:shift"); break;
2472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Widen the value to be shifted to 32 bits, do the shift, and
2475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         narrow back down.  This seems surprisingly long-winded, but
2476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unfortunately the Intel semantics requires that 8/16-bit
2477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         shifts give defined results for shift values all the way up
2478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to 31, and this seems the simplest way to do it.  It has the
2479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         advantage that the only IR level shifts generated are of 32
2480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bit values, and the shift amount is guaranteed to be in the
2481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         range 0 .. 31, thereby observing the IR semantics requiring
2482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         all shift values to be in the range 0 .. 2^word_size-1. */
2483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* shift_amt = shift_expr & 31, regardless of operation size */
2485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* suitably widen the value to be shifted to 32 bits. */
2488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     : widenUto32(mkexpr(dst0)) );
2490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* res32 = pre32 `shift` shift_amt */
2492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( res32ss,
2496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(op32,
2497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkexpr(pre32),
2498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And8,
2499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Sub8,
2500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(shift_amt), mkU8(1)),
2501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU8(31))) );
2502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Build the flags thunk. */
2504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
2505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Narrow the result back down. */
2507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst1, narrowTo(ty, mkexpr(res32)) );
2508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* if (isShift) */
2510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isRotate) {
2513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    ccOp      = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
2514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   left      = toBool(gregOfRM(modrm) == 0);
2515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rot_amt   = newTemp(Ity_I8);
2516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rot_amt32 = newTemp(Ity_I8);
2517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldFlags  = newTemp(Ity_I32);
2518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* rot_amt = shift_expr & mask */
2520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* By masking the rotate amount thusly, the IR-level Shl/Shr
2521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         expressions never shift beyond the word size and thus remain
2522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         well defined. */
2523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ty == Ity_I32)
2526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rot_amt, mkexpr(rot_amt32));
2527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
2528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
2529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (left) {
2531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1,
2534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( mkSizedOp(ty,Iop_Or8),
2535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( mkSizedOp(ty,Iop_Shl8),
2536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(dst0),
2537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(rot_amt)
2538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ),
2539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( mkSizedOp(ty,Iop_Shr8),
2540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(dst0),
2541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )
2543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
2544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
2545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ccOp += X86G_CC_OP_ROLB;
2546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else { /* right */
2548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1,
2551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( mkSizedOp(ty,Iop_Or8),
2552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( mkSizedOp(ty,Iop_Shr8),
2553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(dst0),
2554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(rot_amt)
2555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ),
2556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( mkSizedOp(ty,Iop_Shl8),
2557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(dst0),
2558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )
2560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
2561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
2562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ccOp += X86G_CC_OP_RORB;
2563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* dst1 now holds the rotated value.  Build flag thunk.  We
2567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         need the resulting value for this, and the previous flags.
2568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Except don't set it if the rotate count is zero. */
2569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(oldFlags, mk_x86g_calculate_eflags_all());
2571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* CC_DEP1 is the rotated value.  CC_NDEP is flags before. */
2573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,
2574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRExpr_Mux0X( mkexpr(rot_amt32),
2575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRExpr_Get(OFFB_CC_OP,Ity_I32),
2576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkU32(ccOp))) );
2577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1,
2578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRExpr_Mux0X( mkexpr(rot_amt32),
2579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
2580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      widenUto32(mkexpr(dst1)))) );
2581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2,
2582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRExpr_Mux0X( mkexpr(rot_amt32),
2583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
2584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkU32(0))) );
2585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP,
2586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRExpr_Mux0X( mkexpr(rot_amt32),
2587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRExpr_Get(OFFB_CC_NDEP,Ity_I32),
2588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkexpr(oldFlags))) );
2589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* if (isRotate) */
2590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Save result, and finish up. */
2592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
2593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (vex_traceflags & VEX_TRACE_FE) {
2595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("%s%c ",
2596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    nameGrp2(gregOfRM(modrm)), nameISize(sz) );
2597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (shift_expr_txt)
2598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vex_printf("%s", shift_expr_txt);
2599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ppIRExpr(shift_expr);
2601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE(mkexpr(addr), mkexpr(dst1));
2605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (vex_traceflags & VEX_TRACE_FE) {
2606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("%s%c ",
2607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    nameGrp2(gregOfRM(modrm)), nameISize(sz) );
2608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (shift_expr_txt)
2609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vex_printf("%s", shift_expr_txt);
2610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ppIRExpr(shift_expr);
2612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf(", %s\n", dis_buf);
2613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
2616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_Grp8_Imm ( UChar sorb,
2622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool locked,
2623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int delta, UChar modrm,
2624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int am_sz, Int sz, UInt src_val,
2625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool* decode_OK )
2626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* src_val denotes a d8.
2628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      And delta on entry points at the modrm byte. */
2629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty     = szToITy(sz);
2631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2     = newTemp(Ity_I32);
2632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2m    = newTemp(Ity_I32);
2633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t_addr = IRTemp_INVALID;
2634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
2635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   mask;
2636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* we're optimists :-) */
2638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True;
2639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Limit src_val -- the bit offset -- to something within a word.
2641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      The Intel docs say that literal offsets larger than a word are
2642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      masked in this way. */
2643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
2644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:  src_val &= 15; break;
2645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:  src_val &= 31; break;
2646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: *decode_OK = False; return delta;
2647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Invent a mask suitable for the operation. */
2650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregOfRM(modrm)) {
2651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: /* BT */  mask = 0;               break;
2652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5: /* BTS */ mask = 1 << src_val;    break;
2653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: /* BTR */ mask = ~(1 << src_val); break;
2654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7: /* BTC */ mask = 1 << src_val;    break;
2655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If this needs to be extended, probably simplest to make a
2656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            new function to handle the other cases (0 .. 3).  The
2657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Intel docs do however not indicate any use for 0 .. 3, so
2658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            we don't expect this to happen. */
2659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: *decode_OK = False; return delta;
2660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Fetch the value to be tested and modified into t2, which is
2663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      32-bits wide regardless of sz. */
2664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
2665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(am_sz == 1);
2666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t2, widenUto32(getIReg(sz, eregOfRM(modrm))) );
2667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += (am_sz + 1);
2668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              src_val, nameIReg(sz,eregOfRM(modrm)));
2670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int len;
2672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_addr = disAMode ( &len, sorb, delta, dis_buf);
2673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta  += (len+1);
2674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t2, widenUto32(loadLE(ty, mkexpr(t_addr))) );
2675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              src_val, dis_buf);
2677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Compute the new value into t2m, if non-BT. */
2680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregOfRM(modrm)) {
2681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: /* BT */
2682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5: /* BTS */
2684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2m, binop(Iop_Or32, mkU32(mask), mkexpr(t2)) );
2685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: /* BTR */
2687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2m, binop(Iop_And32, mkU32(mask), mkexpr(t2)) );
2688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7: /* BTC */
2690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2m, binop(Iop_Xor32, mkU32(mask), mkexpr(t2)) );
2691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
2693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/ /*the previous switch guards this*/
2694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
2695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Write the result back, if non-BT.  If the CAS fails then we
2698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      side-exit from the trace at this point, and so the flag state is
2699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      not affected.  This is of course as required. */
2700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (gregOfRM(modrm) != 4 /* BT */) {
2701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
2702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(sz, eregOfRM(modrm), narrowTo(ty, mkexpr(t2m)));
2703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (locked) {
2705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            casLE( mkexpr(t_addr),
2706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   narrowTo(ty, mkexpr(t2))/*expd*/,
2707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   narrowTo(ty, mkexpr(t2m))/*new*/,
2708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   guest_EIP_curr_instr );
2709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
2711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Copy relevant bit from t2 into the carry flag. */
2716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
2717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
2718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
2720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_CC_DEP1,
2721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And32,
2722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Shr32, mkexpr(t2), mkU8(src_val)),
2723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU32(1))
2724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ));
2725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
2726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
2727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
2728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
2730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Signed/unsigned widening multiply.  Generate IR to multiply the
2734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   value in EAX/AX/AL by the given IRTemp, and park the result in
2735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   EDX:EAX/DX:AX/AX.
2736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void codegen_mulL_A_D ( Int sz, Bool syned,
2738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               IRTemp tmp, HChar* tmp_txt )
2739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
2741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1 = newTemp(ty);
2742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t1, getIReg(sz, R_EAX) );
2744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (ty) {
2746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: {
2747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res64   = newTemp(Ity_I64);
2748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resHi   = newTemp(Ity_I32);
2749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resLo   = newTemp(Ity_I32);
2750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   mulOp   = syned ? Iop_MullS32 : Iop_MullU32;
2751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
2752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
2753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resLo, unop(Iop_64to32,mkexpr(res64)));
2756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EDX, mkexpr(resHi));
2757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EAX, mkexpr(resLo));
2758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: {
2761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res32   = newTemp(Ity_I32);
2762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resHi   = newTemp(Ity_I16);
2763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resLo   = newTemp(Ity_I16);
2764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   mulOp   = syned ? Iop_MullS16 : Iop_MullU16;
2765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
2766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
2767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resLo, unop(Iop_32to16,mkexpr(res32)));
2770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(2, R_EDX, mkexpr(resHi));
2771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(2, R_EAX, mkexpr(resLo));
2772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8: {
2775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res16   = newTemp(Ity_I16);
2776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resHi   = newTemp(Ity_I8);
2777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resLo   = newTemp(Ity_I8);
2778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   mulOp   = syned ? Iop_MullS8 : Iop_MullU8;
2779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
2780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
2781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resLo, unop(Iop_16to8,mkexpr(res16)));
2784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(2, R_EAX, mkexpr(res16));
2785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
2788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("codegen_mulL_A_D(x86)");
2789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
2791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 3 extended opcodes. */
2795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_Grp3 ( UChar sorb, Bool locked, Int sz, Int delta, Bool* decode_OK )
2797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt    d32;
2799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   modrm;
2800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
2801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
2802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
2803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty = szToITy(sz);
2804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  t1 = newTemp(ty);
2805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst1, src, dst0;
2806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True; /* may change this later */
2808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm = getIByte(delta);
2810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (locked && (gregOfRM(modrm) != 2 && gregOfRM(modrm) != 3)) {
2812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LOCK prefix only allowed with not and neg subopcodes */
2813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decode_OK = False;
2814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta;
2815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
2818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
2819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: { /* TEST */
2820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++; d32 = getUDisp(sz, delta); delta += sz;
2821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
2822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               getIReg(sz,eregOfRM(modrm)),
2824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU(ty,d32)));
2825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1( Iop_And8, dst1, ty );
2826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      nameIReg(sz, eregOfRM(modrm)));
2828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* UNDEFINED */
2831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           /* The Intel docs imply this insn is undefined and binutils
2832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              agrees.  Unfortunately Core 2 will run it (with who
2833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              knows what result?)  sandpile.org reckons it's an alias
2834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              for case 0.  We play safe. */
2835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *decode_OK = False;
2836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
2837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: /* NOT */
2838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
2839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(sz, eregOfRM(modrm),
2840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(mkSizedOp(ty,Iop_Not8),
2841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             getIReg(sz, eregOfRM(modrm))));
2842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: /* NEG */
2845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
2846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst0 = newTemp(ty);
2847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            src  = newTemp(ty);
2848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
2849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst0, mkU(ty,0));
2850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(src,  getIReg(sz,eregOfRM(modrm)));
2851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
2852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
2853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: /* MUL (unsigned widening) */
2857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
2858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            src = newTemp(ty);
2859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(src, getIReg(sz,eregOfRM(modrm)));
2860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
2861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 5: /* IMUL (signed widening) */
2863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
2864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            src = newTemp(ty);
2865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(src, getIReg(sz,eregOfRM(modrm)));
2866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
2867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 6: /* DIV */
2869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
2870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, getIReg(sz, eregOfRM(modrm)) );
2871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_div ( sz, t1, False );
2872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 7: /* IDIV */
2875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
2876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, getIReg(sz, eregOfRM(modrm)) );
2877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_div ( sz, t1, True );
2878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
2881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* This can't happen - gregOfRM should return 0 .. 7 only */
2882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("Grp3(x86)");
2883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta, dis_buf );
2886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1   = newTemp(ty);
2887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
2888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, loadLE(ty,mkexpr(addr)));
2889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
2890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: { /* TEST */
2891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            d32 = getUDisp(sz, delta); delta += sz;
2892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
2893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(t1), mkU(ty,d32)));
2895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1( Iop_And8, dst1, ty );
2896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* UNDEFINED */
2900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           /* See comment above on R case */
2901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *decode_OK = False;
2902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
2903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: /* NOT */
2904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
2905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
2907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    guest_EIP_curr_instr );
2909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
2910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), mkexpr(dst1) );
2911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("not%c %s\n", nameISize(sz), dis_buf);
2913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: /* NEG */
2915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst0 = newTemp(ty);
2916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            src  = newTemp(ty);
2917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
2918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst0, mkU(ty,0));
2919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(src,  mkexpr(t1));
2920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, binop(mkSizedOp(ty,Iop_Sub8),
2921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(dst0), mkexpr(src)));
2922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
2923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    guest_EIP_curr_instr );
2925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
2926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), mkexpr(dst1) );
2927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
2929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("neg%c %s\n", nameISize(sz), dis_buf);
2930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: /* MUL */
2932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_mulL_A_D ( sz, False, t1, dis_buf );
2933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 5: /* IMUL */
2935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_mulL_A_D ( sz, True, t1, dis_buf );
2936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 6: /* DIV */
2938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_div ( sz, t1, False );
2939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("div%c %s\n", nameISize(sz), dis_buf);
2940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 7: /* IDIV */
2942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_div ( sz, t1, True );
2943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
2946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* This can't happen - gregOfRM should return 0 .. 7 only */
2947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("Grp3(x86)");
2948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
2951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 4 extended opcodes. */
2955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_Grp4 ( UChar sorb, Bool locked, Int delta, Bool* decode_OK )
2957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   alen;
2959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar modrm;
2960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
2961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = Ity_I8;
2962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1 = newTemp(ty);
2963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2 = newTemp(ty);
2964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True;
2966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm = getIByte(delta);
2968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
2970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LOCK prefix only allowed with inc and dec subopcodes */
2971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decode_OK = False;
2972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta;
2973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
2976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIReg(1, eregOfRM(modrm)));
2977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
2978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: /* INC */
2979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(1, eregOfRM(modrm), mkexpr(t2));
2981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( True, t2, ty );
2982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* DEC */
2984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(1, eregOfRM(modrm), mkexpr(t2));
2986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( False, t2, ty );
2987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
2989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
2990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
2991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
2993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
2994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameIReg(1, eregOfRM(modrm)));
2995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
2997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, loadLE(ty, mkexpr(addr)) );
2998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
2999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: /* INC */
3000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
3002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_EIP_curr_instr );
3004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), mkexpr(t2) );
3006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( True, t2, ty );
3008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* DEC */
3010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
3012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_EIP_curr_instr );
3014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), mkexpr(t2) );
3016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( False, t2, ty );
3018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
3020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
3021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
3022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
3024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
3025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
3027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 5 extended opcodes. */
3031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_Grp5 ( UChar sorb, Bool locked, Int sz, Int delta,
3033663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                /*MOD*/DisResult* dres, /*OUT*/Bool* decode_OK )
3034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
3036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   modrm;
3037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
3038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr = IRTemp_INVALID;
3039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty = szToITy(sz);
3040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  t1 = newTemp(ty);
3041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  t2 = IRTemp_INVALID;
3042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True;
3044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm = getIByte(delta);
3046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
3048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LOCK prefix only allowed with inc and dec subopcodes */
3049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decode_OK = False;
3050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta;
3051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
3054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIReg(sz,eregOfRM(modrm)));
3055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
3056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: /* INC */
3057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 2 || sz == 4);
3058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(ty);
3059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t1), mkU(ty,1)));
3061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( True, t2, ty );
3062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(sz,eregOfRM(modrm),mkexpr(t2));
3063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* DEC */
3065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 2 || sz == 4);
3066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(ty);
3067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t1), mkU(ty,1)));
3069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( False, t2, ty );
3070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(sz,eregOfRM(modrm),mkexpr(t2));
3071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: /* call Ev */
3073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 4);
3074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I32);
3075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(4, R_ESP, mkexpr(t2));
3077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+1));
3078663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_treg(dres, Ijk_Call, t1);
3079663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres->whatNext == Dis_StopHere);
3080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: /* jmp Ev */
3082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 4);
3083663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_treg(dres, Ijk_Boring, t1);
3084663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres->whatNext == Dis_StopHere);
3085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 6: /* PUSH Ev */
3087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 4 || sz == 2);
3088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I32);
3089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(4, R_ESP, mkexpr(t2) );
3091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(t2), mkexpr(t1) );
3092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
3094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
3095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
3096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
3098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
3100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta, dis_buf );
3102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, loadLE(ty,mkexpr(addr)));
3103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
3104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: /* INC */
3105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(ty);
3106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t1), mkU(ty,1)));
3108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
3109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr),
3110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr),mkexpr(t2));
3113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( True, t2, ty );
3115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* DEC */
3117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(ty);
3118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t1), mkU(ty,1)));
3120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
3121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr),
3122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr),mkexpr(t2));
3125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( False, t2, ty );
3127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: /* call Ev */
3129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 4);
3130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I32);
3131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(4, R_ESP, mkexpr(t2));
3133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+len));
3134663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_treg(dres, Ijk_Call, t1);
3135663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres->whatNext == Dis_StopHere);
3136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: /* JMP Ev */
3138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 4);
3139663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_treg(dres, Ijk_Boring, t1);
3140663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres->whatNext == Dis_StopHere);
3141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 6: /* PUSH Ev */
3143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 4 || sz == 2);
3144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I32);
3145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(4, R_ESP, mkexpr(t2) );
3147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(t2), mkexpr(t1) );
3148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
3150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
3151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
3152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
3154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       nameISize(sz), dis_buf);
3156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
3158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassembling string ops (including REP prefixes)    ---*/
3163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Code shared by all the string ops */
3166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_string_op_increment(Int sz, Int t_inc)
3168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 || sz == 2) {
3170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_inc,
3171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
3172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(sz/2) ) );
3173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_inc,
3175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
3176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_string_op( void (*dis_OP)( Int, IRTemp ),
3181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int sz, HChar* name, UChar sorb )
3182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t_inc = newTemp(Ity_I32);
3184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sorb == 0); /* hmm.  so what was the point of passing it in? */
3185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dis_string_op_increment(sz, t_inc);
3186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dis_OP( sz, t_inc );
3187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%c\n", name, nameISize(sz));
3188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_MOVS ( Int sz, IRTemp t_inc )
3192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
3194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp td = newTemp(Ity_I32);   /* EDI */
3195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ts = newTemp(Ity_I32);   /* ESI */
3196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( td, getIReg(4, R_EDI) );
3198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ts, getIReg(4, R_ESI) );
3199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_LODS ( Int sz, IRTemp t_inc )
3208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
3210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ts = newTemp(Ity_I32);   /* ESI */
3211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ts, getIReg(4, R_ESI) );
3213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( sz, R_EAX, loadLE(ty, mkexpr(ts)) );
3215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_STOS ( Int sz, IRTemp t_inc )
3221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
3223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ta = newTemp(ty);        /* EAX */
3224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp td = newTemp(Ity_I32);   /* EDI */
3225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ta, getIReg(sz, R_EAX) );
3227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( td, getIReg(4, R_EDI) );
3228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   storeLE( mkexpr(td), mkexpr(ta) );
3230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_CMPS ( Int sz, IRTemp t_inc )
3236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty  = szToITy(sz);
3238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tdv = newTemp(ty);      /* (EDI) */
3239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tsv = newTemp(ty);      /* (ESI) */
3240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp td  = newTemp(Ity_I32); /*  EDI  */
3241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ts  = newTemp(Ity_I32); /*  ESI  */
3242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( td, getIReg(4, R_EDI) );
3244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ts, getIReg(4, R_ESI) );
3245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tdv, loadLE(ty,mkexpr(td)) );
3247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tsv, loadLE(ty,mkexpr(ts)) );
3248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
3250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_SCAS ( Int sz, IRTemp t_inc )
3257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty  = szToITy(sz);
3259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ta  = newTemp(ty);       /*  EAX  */
3260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp td  = newTemp(Ity_I32);  /*  EDI  */
3261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tdv = newTemp(ty);       /* (EDI) */
3262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ta, getIReg(sz, R_EAX) );
3264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( td, getIReg(4, R_EDI) );
3265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tdv, loadLE(ty,mkexpr(td)) );
3267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
3268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Wrap the appropriate string op inside a REP/REPE/REPNE.
3274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   We assume the insn is the last one in the basic block, and so emit a jump
3275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to the next insn, rather than just falling through. */
3276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3277663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengvoid dis_REP_op ( /*MOD*/DisResult* dres,
3278663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                  X86Condcode cond,
3279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  void (*dis_OP)(Int, IRTemp),
3280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Int sz, Addr32 eip, Addr32 eip_next, HChar* name )
3281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t_inc = newTemp(Ity_I32);
3283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tc    = newTemp(Ity_I32);  /*  ECX  */
3284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tc, getIReg(4,R_ECX) );
3286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
3288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ijk_Boring,
3289663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                      IRConst_U32(eip_next), OFFB_EIP ) );
3290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
3292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dis_string_op_increment(sz, t_inc);
3294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dis_OP (sz, t_inc);
3295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cond == X86CondAlways) {
3297663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      jmp_lit(dres, Ijk_Boring, eip);
3298663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vassert(dres->whatNext == Dis_StopHere);
3299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
3301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Ijk_Boring,
3302663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         IRConst_U32(eip), OFFB_EIP ) );
3303663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      jmp_lit(dres, Ijk_Boring, eip_next);
3304663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vassert(dres->whatNext == Dis_StopHere);
3305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%c\n", name, nameISize(sz));
3307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Arithmetic, etc.                                     ---*/
3312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* IMUL E, G.  Supplied eip points to the modR/M byte. */
3315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_mul_E_G ( UChar       sorb,
3317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         size,
3318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         delta0 )
3319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    alen;
3321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
3322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  rm = getIByte(delta0);
3323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(size);
3324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp te = newTemp(ty);
3325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tg = newTemp(ty);
3326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp resLo = newTemp(ty);
3327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tg, getIReg(size, gregOfRM(rm)) );
3329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
3330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( te, getIReg(size, eregOfRM(rm)) );
3331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( te, loadLE(ty,mkexpr(addr)) );
3334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
3337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
3339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
3343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("imul%c %s, %s\n", nameISize(size),
3344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             nameIReg(size,eregOfRM(rm)),
3345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             nameIReg(size,gregOfRM(rm)));
3346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
3347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("imul%c %s, %s\n", nameISize(size),
3349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             dis_buf, nameIReg(size,gregOfRM(rm)));
3350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return alen+delta0;
3351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* IMUL I * E -> G.  Supplied eip points to the modR/M byte. */
3356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_imul_I_E_G ( UChar       sorb,
3358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Int         size,
3359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Int         delta,
3360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Int         litsize )
3361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    d32, alen;
3363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
3364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  rm = getIByte(delta);
3365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(size);
3366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp te = newTemp(ty);
3367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tl = newTemp(ty);
3368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp resLo = newTemp(ty);
3369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(size == 1 || size == 2 || size == 4);
3371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
3373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(te, getIReg(size, eregOfRM(rm)));
3374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
3375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(te, loadLE(ty, mkexpr(addr)));
3378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
3379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   d32 = getSDisp(litsize,delta);
3381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta += litsize;
3382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (size == 1) d32 &= 0xFF;
3384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (size == 2) d32 &= 0xFFFF;
3385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(tl, mkU(ty,d32));
3387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
3389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
3391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(size, gregOfRM(rm), mkexpr(resLo));
3393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("imul %d, %s, %s\n", d32,
3395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameIReg(size,gregOfRM(rm)) );
3397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
3398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate an IR sequence to do a count-leading-zeroes operation on
3402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the supplied IRTemp, and return a new IRTemp holding the result.
3403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'ty' may be Ity_I16 or Ity_I32 only.  In the case where the
3404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   argument is zero, return the number of bits in the word (the
3405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   natural semantics). */
3406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp gen_LZCNT ( IRType ty, IRTemp src )
3407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(ty == Ity_I32 || ty == Ity_I16);
3409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src32 = newTemp(Ity_I32);
3411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(src32, widenUto32( mkexpr(src) ));
3412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src32x = newTemp(Ity_I32);
3414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(src32x,
3415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Shl32, mkexpr(src32),
3416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU8(32 - 8 * sizeofIRType(ty))));
3417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Clz32 has undefined semantics when its input is zero, so
3419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // special-case around that.
3420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res32 = newTemp(Ity_I32);
3421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(res32,
3422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          IRExpr_Mux0X(
3423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             unop(Iop_1Uto8,
3424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_CmpEQ32, mkexpr(src32x), mkU32(0))),
3425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             unop(Iop_Clz32, mkexpr(src32x)),
3426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkU32(8 * sizeofIRType(ty))
3427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ));
3428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res = newTemp(ty);
3430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(res, narrowTo(ty, mkexpr(res32)));
3431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
3432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
3437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- x87 FLOATING POINT INSTRUCTIONS                      ---*/
3438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
3439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Helper functions for dealing with the register stack. --- */
3442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Set the emulation-warning pseudo-register. --- */
3444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
3448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
3452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkQNaN64 ( void )
3454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* QNaN is 0 2047 1 0(51times)
3456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     == 0b 11111111111b 1 0(51times)
3457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     == 0x7FF8 0000 0000 0000
3458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
3459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
3460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/put the top-of-stack pointer. --------- */
3463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_ftop ( void )
3465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_ftop ( IRExpr* e )
3470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
3472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_FTOP, e ) );
3473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/put the C3210 bits. --------- */
3476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_C3210 ( void )
3478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( OFFB_FC3210, Ity_I32 );
3480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_C3210 ( IRExpr* e )
3483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_FC3210, e ) );
3485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/put the FPU rounding mode. --------- */
3488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* /* :: Ity_I32 */ get_fpround ( void )
3489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
3491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
3494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_FPROUND, e ) );
3496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
3500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Produces a value in 0 .. 3, which is encoded as per the type
3501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRoundingMode.  Since the guest_FPROUND value is also encoded as
3502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   per IRRoundingMode, we merely need to get it and mask it for
3503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   safety.
3504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return binop( Iop_And32, get_fpround(), mkU32(3) );
3508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
3511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return mkU32(Irrm_NEAREST);
3513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/set FP register tag bytes. --------- */
3517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_ST_TAG ( Int i, IRExpr* value )
3521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr;
3523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_I8);
3524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
3525663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   stmt( IRStmt_PutI( mkIRPutI(descr, get_ftop(), i, value) ) );
3526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, generate an expression yielding 'ST_TAG(i)'.  This will be
3529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   zero to indicate "Empty" and nonzero to indicate "NonEmpty".  */
3530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_ST_TAG ( Int i )
3532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
3534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_GetI( descr, get_ftop(), i );
3535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/set FP registers. --------- */
3539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, and some expression e, emit 'ST(i) = e' and set the
3541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register's tag to indicate the register is full.  The previous
3542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   state of the register is not checked. */
3543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_ST_UNCHECKED ( Int i, IRExpr* value )
3545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr;
3547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_F64);
3548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
3549663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   stmt( IRStmt_PutI( mkIRPutI(descr, get_ftop(), i, value) ) );
3550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Mark the register as in-use. */
3551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_TAG(i, mkU8(1));
3552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, and some expression e, emit
3555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ST(i) = is_full(i) ? NaN : e
3556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and set the tag accordingly.
3557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_ST ( Int i, IRExpr* value )
3560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_UNCHECKED( i,
3562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRExpr_Mux0X( get_ST_TAG(i),
3563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   /* 0 means empty */
3564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   value,
3565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   /* non-0 means full */
3566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkQNaN64()
3567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )
3568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
3569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, generate an expression yielding 'ST(i)'. */
3573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_ST_UNCHECKED ( Int i )
3575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
3577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_GetI( descr, get_ftop(), i );
3578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, generate an expression yielding
3582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  is_full(i) ? ST(i) : NaN
3583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_ST ( Int i )
3586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
3588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr_Mux0X( get_ST_TAG(i),
3589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    /* 0 means empty */
3590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkQNaN64(),
3591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    /* non-0 means full */
3592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    get_ST_UNCHECKED(i));
3593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Adjust FTOP downwards by one register. */
3597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void fp_push ( void )
3599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
3601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Adjust FTOP upwards by one register, and mark the vacated register
3604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   as empty.  */
3605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void fp_pop ( void )
3607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_TAG(0, mkU8(0));
3609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
3610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Clear the C2 bit of the FPU status register, for
3613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sin/cos/tan/sincos. */
3614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void clear_C2 ( void )
3616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_C3210( binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2)) );
3618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Invent a plausible-looking FPU status word value:
3621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ((ftop & 7) << 11) | (c3210 & 0x4700)
3622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
3623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_FPU_sw ( void )
3624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
3626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unop(Iop_32to16,
3627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_Or32,
3628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Shl32,
3629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And32, get_ftop(), mkU32(7)),
3630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU8(11)),
3631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And32, get_C3210(), mkU32(0x4700))
3632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ));
3633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------------------------------------------------- */
3637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given all that stack-mangling junk, we can now go ahead
3638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and describe FP instructions.
3639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ST(0) = ST(0) `op` mem64/32(addr)
3642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Need to check ST(0)'s tag on read, but not on write.
3643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
3646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IROp op, Bool dbl )
3647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
3649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (dbl) {
3650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ST_UNCHECKED(0,
3651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         triop( op,
3652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_ST(0),
3654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                loadLE(Ity_F64,mkexpr(addr))
3655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
3656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ST_UNCHECKED(0,
3658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         triop( op,
3659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_ST(0),
3661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
3663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ST(0) = mem64/32(addr) `op` ST(0)
3668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Need to check ST(0)'s tag on read, but not on write.
3669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
3672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            IROp op, Bool dbl )
3673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
3675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (dbl) {
3676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ST_UNCHECKED(0,
3677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         triop( op,
3678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                loadLE(Ity_F64,mkexpr(addr)),
3680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_ST(0)
3681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
3682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ST_UNCHECKED(0,
3684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         triop( op,
3685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_ST(0)
3688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
3689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ST(dst) = ST(dst) `op` ST(src).
3694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Check dst and src tags when reading but not on write.
3695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
3698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Bool pop_after )
3699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 (Int)st_src, (Int)st_dst );
3702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_UNCHECKED(
3703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      st_dst,
3704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      triop( op,
3705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_ST(st_dst),
3707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_ST(st_src) )
3708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
3709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pop_after)
3710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fp_pop();
3711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ST(dst) = ST(src) `op` ST(dst).
3714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Check dst and src tags when reading but not on write.
3715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
3718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Bool pop_after )
3719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 (Int)st_src, (Int)st_dst );
3722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_UNCHECKED(
3723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      st_dst,
3724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      triop( op,
3725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_ST(st_src),
3727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_ST(st_dst) )
3728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
3729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pop_after)
3730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fp_pop();
3731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", (Int)i );
3737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is a bit of a hack (and isn't really right).  It sets
3738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      documentation implies A and S are unchanged.
3740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
3741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* It's also fishy in that it is used both for COMIP and
3742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UCOMIP, and they aren't the same (although similar). */
3743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
3744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
3745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1,
3746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop( Iop_And32,
3747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(0x45)
3749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       )));
3750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
3751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
3752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
3753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pop_after)
3754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fp_pop();
3755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
3760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    len;
3762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   r_src, r_dst;
3763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
3764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1, t2;
3765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* On entry, delta points at the second byte of the insn (the modrm
3767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      byte).*/
3768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar first_opcode = getIByte(delta-1);
3769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar modrm        = getIByte(delta+0);
3770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xD8) {
3774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
3775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
3777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           specifies an address. */
3778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
3780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
3782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FADD single-real */
3784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FMUL single-real */
3788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FCOM single-real */
3792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcoms %s\n", dis_buf);
3793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
3794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
3795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
3796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
3797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
3798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
3799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      unop(Iop_F32toF64,
3800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           loadLE(Ity_F32,mkexpr(addr)))),
3801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
3802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
3803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
3804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FCOMP single-real */
3807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcomps %s\n", dis_buf);
3808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
3809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
3810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
3811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
3812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
3813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
3814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      unop(Iop_F32toF64,
3815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           loadLE(Ity_F32,mkexpr(addr)))),
3816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
3817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
3818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
3819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
3820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: /* FSUB single-real */
3823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FSUBR single-real */
3827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: /* FDIV single-real */
3831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FDIVR single-real */
3835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
3839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xD8\n");
3841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
3842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
3844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
3845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
3846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
3848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
3849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Dunno if this is right */
3856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xD0;
3858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcom %%st(0),%%st(%d)\n", (Int)r_dst);
3859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
3860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
3861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
3862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
3863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
3865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
3866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
3867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Dunno if this is right */
3870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xD8;
3872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcomp %%st(0),%%st(%d)\n", (Int)r_dst);
3873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
3874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
3875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
3876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
3877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
3879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
3880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
3881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
3882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
3885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
3886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
3901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
3902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
3908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xD9) {
3909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
3910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
3912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
3913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
3915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
3917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FLD single-real */
3919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("flds %s\n", dis_buf);
3920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
3921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, unop(Iop_F32toF64,
3922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              loadLE(Ity_F32, mkexpr(addr))));
3923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FST single-real */
3926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fsts %s\n", dis_buf);
3927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr),
3928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
3929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FSTP single-real */
3932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstps %s\n", dis_buf);
3933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr),
3934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
3935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
3936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: { /* FLDENV m28 */
3939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
3940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, HWord ) */
3941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp   ew = newTemp(Ity_I32);
3942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d  = unsafeIRDirty_0_N (
3943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                0/*regparms*/,
3944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                "x86g_dirtyhelper_FLDENV",
3945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                &x86g_dirtyhelper_FLDENV,
3946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkIRExprVec_1( mkexpr(addr) )
3947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             );
3948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->needsBBP = True;
3949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->tmp      = ew;
3950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're reading memory */
3951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Read;
3952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
3953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 28;
3954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing guest state */
3956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->nFxState = 4;
3957663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               vex_bzero(&d->fxState, sizeof(d->fxState));
3958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].fx     = Ifx_Write;
3960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].offset = OFFB_FTOP;
3961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].size   = sizeof(UInt);
3962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].fx     = Ifx_Write;
3964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].offset = OFFB_FPTAGS;
3965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].size   = 8 * sizeof(UChar);
3966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].fx     = Ifx_Write;
3968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].offset = OFFB_FPROUND;
3969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].size   = sizeof(UInt);
3970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].fx     = Ifx_Write;
3972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].offset = OFFB_FC3210;
3973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].size   = sizeof(UInt);
3974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
3976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* ew contains any emulation warning we may need to
3978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  issue.  If needed, side-exit to the next insn,
3979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  reporting the warning, so that Valgrind's dispatcher
3980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  sees the warning. */
3981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_emwarn( mkexpr(ew) );
3982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt(
3983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRStmt_Exit(
3984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_EmWarn,
3986663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
3987663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     OFFB_EIP
3988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
3989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
3990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldenv %s\n", dis_buf);
3992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: {/* FLDCW */
3996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* The only thing we observe in the control word is the
3997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  rounding mode.  Therefore, pass the 16-bit value
3998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (x87 native-format control word) to a clean helper,
3999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getting back a 64-bit value, the lower half of which
4000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  is the FPROUND value to store, and the upper half of
4001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  which is the emulation-warning token which may be
4002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  generated.
4003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               */
4004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* ULong x86h_check_fldcw ( UInt ); */
4005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp t64 = newTemp(Ity_I64);
4006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp ew = newTemp(Ity_I32);
4007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldcw %s\n", dis_buf);
4008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( t64, mkIRExprCCall(
4009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               Ity_I64, 0/*regparms*/,
4010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "x86g_check_fldcw",
4011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &x86g_check_fldcw,
4012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkIRExprVec_1(
4013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  unop( Iop_16Uto32,
4014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        loadLE(Ity_I16, mkexpr(addr)))
4015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               )
4016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            )
4017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
4018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_fpround( unop(Iop_64to32, mkexpr(t64)) );
4020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
4021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_emwarn( mkexpr(ew) );
4022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Finally, if an emulation warning was reported,
4023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  side-exit to the next insn, reporting the warning,
4024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  so that Valgrind's dispatcher sees the warning. */
4025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt(
4026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRStmt_Exit(
4027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_EmWarn,
4029663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
4030663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     OFFB_EIP
4031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
4032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
4033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: { /* FNSTENV m28 */
4037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
4038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     void x86g_do_FSTENV ( VexGuestX86State*, HWord ) */
4039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d = unsafeIRDirty_0_N (
4040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               0/*regparms*/,
4041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "x86g_dirtyhelper_FSTENV",
4042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &x86g_dirtyhelper_FSTENV,
4043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkIRExprVec_1( mkexpr(addr) )
4044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            );
4045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->needsBBP = True;
4046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing memory */
4047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Write;
4048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
4049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 28;
4050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're reading guest state */
4052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->nFxState = 4;
4053663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               vex_bzero(&d->fxState, sizeof(d->fxState));
4054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].fx     = Ifx_Read;
4056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].offset = OFFB_FTOP;
4057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].size   = sizeof(UInt);
4058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].fx     = Ifx_Read;
4060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].offset = OFFB_FPTAGS;
4061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].size   = 8 * sizeof(UChar);
4062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].fx     = Ifx_Read;
4064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].offset = OFFB_FPROUND;
4065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].size   = sizeof(UInt);
4066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].fx     = Ifx_Read;
4068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].offset = OFFB_FC3210;
4069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].size   = sizeof(UInt);
4070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
4072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnstenv %s\n", dis_buf);
4074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FNSTCW */
4078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              /* Fake up a native x87 FPU control word.  The only
4079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 thing it depends on is FPROUND[1:0], so call a clean
4080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 helper to cook it up. */
4081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* UInt x86h_create_fpucw ( UInt fpround ) */
4082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnstcw %s\n", dis_buf);
4083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(
4084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkexpr(addr),
4085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop( Iop_32to16,
4086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkIRExprCCall(
4087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Ity_I32, 0/*regp*/,
4088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           "x86g_create_fpucw", &x86g_create_fpucw,
4089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkIRExprVec_1( get_fpround() )
4090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        )
4091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
4092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
4093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xD9\n");
4098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
4102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
4103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
4104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FLD %st(?) */
4106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC0;
4107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fld %%st(%d)\n", (Int)r_src);
4108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               t1 = newTemp(Ity_F64);
4109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(t1, get_ST(r_src));
4110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, mkexpr(t1));
4112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FXCH %st(?) */
4115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC8;
4116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fxch %%st(%d)\n", (Int)r_src);
4117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               t1 = newTemp(Ity_F64);
4118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               t2 = newTemp(Ity_F64);
4119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(t1, get_ST(0));
4120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(t2, get_ST(r_src));
4121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0, mkexpr(t2));
4122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(r_src, mkexpr(t1));
4123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0: /* FCHS */
4126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fchs\n");
4127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE1: /* FABS */
4131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fabs\n");
4132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE4: /* FTST */
4136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ftst\n");
4137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Well, in fact the Intel docs say (bizarrely): "C1 is
4139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  set to 0 if stack underflow occurred; otherwise, set
4140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  to 0" which is pretty nonsensical.  I guess it's a
4141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   typo. */
4142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
4144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
4145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
4146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
4147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRExpr_Const(IRConst_F64i(0x0ULL))),
4148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
4149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
4150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
4151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE5: { /* FXAM */
4154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This is an interesting one.  It examines %st(0),
4155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  regardless of whether the tag says it's empty or not.
4156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Here, just pass both the tag (in our format) and the
4157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  value (as a double, actually a ULong) to a helper
4158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  function. */
4159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr** args
4160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
4161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   unop(Iop_ReinterpF64asI64,
4162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        get_ST_UNCHECKED(0)) );
4163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(mkIRExprCCall(
4164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Ity_I32,
4165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            0/*regparm*/,
4166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            "x86g_calculate_FXAM", &x86g_calculate_FXAM,
4167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            args
4168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        ));
4169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fxam\n");
4170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8: /* FLD1 */
4174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fld1\n");
4175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
4177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
4178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE9: /* FLDL2T */
4181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldl2t\n");
4182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
4184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
4185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xEA: /* FLDL2E */
4188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldl2e\n");
4189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
4191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
4192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xEB: /* FLDPI */
4195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldpi\n");
4196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
4198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
4199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xEC: /* FLDLG2 */
4202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldlg2\n");
4203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
4205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
4206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xED: /* FLDLN2 */
4209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldln2\n");
4210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
4212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
4213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xEE: /* FLDZ */
4216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldz\n");
4217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
4219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
4220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0: /* F2XM1 */
4223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("f2xm1\n");
4224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_2xm1F64,
4226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF1: /* FYL2X */
4231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fyl2x\n");
4232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(1,
4233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_Yl2xF64,
4234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(1),
4236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF2: /* FPTAN */
4241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ftan\n");
4242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_TanF64,
4244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
4248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               clear_C2(); /* HACK */
4249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF3: /* FPATAN */
4252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fpatan\n");
4253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(1,
4254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_AtanF64,
4255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(1),
4257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF4: { /* FXTRACT */
4262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp argF = newTemp(Ity_F64);
4263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp sigF = newTemp(Ity_F64);
4264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp expF = newTemp(Ity_F64);
4265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp argI = newTemp(Ity_I64);
4266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp sigI = newTemp(Ity_I64);
4267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp expI = newTemp(Ity_I64);
4268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fxtract\n");
4269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( argF, get_ST(0) );
4270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
4271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( sigI,
4272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprCCall(
4273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Ity_I64, 0/*regparms*/,
4274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "x86amd64g_calculate_FXTRACT",
4275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          &x86amd64g_calculate_FXTRACT,
4276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkIRExprVec_2( mkexpr(argI),
4277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkIRExpr_HWord(0)/*sig*/ ))
4278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
4279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( expI,
4280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprCCall(
4281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Ity_I64, 0/*regparms*/,
4282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "x86amd64g_calculate_FXTRACT",
4283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          &x86amd64g_calculate_FXTRACT,
4284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkIRExprVec_2( mkexpr(argI),
4285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkIRExpr_HWord(1)/*exp*/ ))
4286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
4287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
4288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
4289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* exponent */
4290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0, mkexpr(expF) );
4291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* significand */
4293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, mkexpr(sigF) );
4294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF5: { /* FPREM1 -- IEEE compliant */
4298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a1 = newTemp(Ity_F64);
4299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a2 = newTemp(Ity_F64);
4300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fprem1\n");
4301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Do FPREM1 twice, once to get the remainder, and once
4302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  to get the C3210 flag values. */
4303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a1, get_ST(0) );
4304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a2, get_ST(1) );
4305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_PRem1F64,
4307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1),
4309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a2)));
4310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_PRem1C3210F64,
4312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1),
4314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a2)) );
4315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF7: /* FINCSTP */
4319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fprem\n");
4320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF8: { /* FPREM -- not IEEE compliant */
4324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a1 = newTemp(Ity_F64);
4325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a2 = newTemp(Ity_F64);
4326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fprem\n");
4327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Do FPREM twice, once to get the remainder, and once
4328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  to get the C3210 flag values. */
4329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a1, get_ST(0) );
4330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a2, get_ST(1) );
4331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_PRemF64,
4333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1),
4335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a2)));
4336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_PRemC3210F64,
4338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1),
4340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a2)) );
4341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF9: /* FYL2XP1 */
4345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fyl2xp1\n");
4346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(1,
4347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_Yl2xp1F64,
4348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(1),
4350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFA: /* FSQRT */
4355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fsqrt\n");
4356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_SqrtF64,
4358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFB: { /* FSINCOS */
4363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a1 = newTemp(Ity_F64);
4364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a1, get_ST(0) );
4365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fsincos\n");
4366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_SinF64,
4368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1)));
4370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0,
4372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_CosF64,
4373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1)));
4375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               clear_C2(); /* HACK */
4376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFC: /* FRNDINT */
4380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("frndint\n");
4381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
4383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFD: /* FSCALE */
4386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fscale\n");
4387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_ScaleF64,
4389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0),
4391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(1)));
4392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFE: /* FSIN */
4395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fsin\n");
4396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_SinF64,
4398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               clear_C2(); /* HACK */
4401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFF: /* FCOS */
4404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcos\n");
4405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_CosF64,
4407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               clear_C2(); /* HACK */
4410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
4420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDA) {
4421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
4423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
4425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
4426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   fop;
4427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
4429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
4430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FIADD m32int */ /* ST(0) += m32int */
4432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fiaddl %s\n", dis_buf);
4433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_AddF64;
4434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m32;
4435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
4437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fimull %s\n", dis_buf);
4438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_MulF64;
4439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m32;
4440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FICOM m32int */
4442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ficoml %s\n", dis_buf);
4443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
4446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
4447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
4448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
4449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      unop(Iop_I32StoF64,
4450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           loadLE(Ity_I32,mkexpr(addr)))),
4451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
4452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
4453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
4454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FICOMP m32int */
4457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ficompl %s\n", dis_buf);
4458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
4461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
4462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
4463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
4464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      unop(Iop_I32StoF64,
4465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           loadLE(Ity_I32,mkexpr(addr)))),
4466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
4467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
4468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
4469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: /* FISUB m32int */ /* ST(0) -= m32int */
4473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubl %s\n", dis_buf);
4474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_SubF64;
4475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m32;
4476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
4478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubrl %s\n", dis_buf);
4479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_SubF64;
4480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_foprev_m32;
4481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
4483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fidivl %s\n", dis_buf);
4484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_DivF64;
4485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m32;
4486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
4488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fidivrl %s\n", dis_buf);
4489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_DivF64;
4490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_foprev_m32;
4491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do_fop_m32:
4493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(fop,
4495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0),
4497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_I32StoF64,
4498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             loadLE(Ity_I32, mkexpr(addr)))));
4499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do_foprev_m32:
4502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(fop,
4504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_I32StoF64,
4506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             loadLE(Ity_I32, mkexpr(addr))),
4507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDA\n");
4513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
4517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
4519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
4520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC0;
4523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovb %%st(%d), %%st(0)\n", (Int)r_src);
4524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Mux0X(
4526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_1Uto8,
4527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mk_x86g_calculate_condition(X86CondB)),
4528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    get_ST(0), get_ST(r_src)) );
4529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC8;
4533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovz %%st(%d), %%st(0)\n", (Int)r_src);
4534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Mux0X(
4536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_1Uto8,
4537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mk_x86g_calculate_condition(X86CondZ)),
4538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    get_ST(0), get_ST(r_src)) );
4539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xD0;
4543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovbe %%st(%d), %%st(0)\n", (Int)r_src);
4544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Mux0X(
4546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_1Uto8,
4547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mk_x86g_calculate_condition(X86CondBE)),
4548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    get_ST(0), get_ST(r_src)) );
4549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
4552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xD8;
4553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovu %%st(%d), %%st(0)\n", (Int)r_src);
4554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Mux0X(
4556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_1Uto8,
4557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mk_x86g_calculate_condition(X86CondP)),
4558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    get_ST(0), get_ST(r_src)) );
4559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE9: /* FUCOMPP %st(0),%st(1) */
4562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fucompp %%st(0),%%st(1)\n");
4563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
4566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
4567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
4569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
4570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
4571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
4584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDB) {
4585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
4586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
4588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
4589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
4591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
4593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FILD m32int */
4595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fildl %s\n", dis_buf);
4596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, unop(Iop_I32StoF64,
4598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              loadLE(Ity_I32, mkexpr(addr))));
4599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FISTTPL m32 (SSE3) */
4602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisttpl %s\n", dis_buf);
4603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
4604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) );
4605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FIST m32 */
4609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistl %s\n", dis_buf);
4610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
4611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
4612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FISTP m32 */
4615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistpl %s\n", dis_buf);
4616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
4617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
4618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: { /* FLD extended-real */
4622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
4623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ULong x86g_loadF80le ( UInt )
4624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  addr holds the address.  First, do a dirty call to
4625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  get hold of the data. */
4626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp   val  = newTemp(Ity_I64);
4627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d = unsafeIRDirty_1_N (
4630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               val,
4631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               0/*regparms*/,
4632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "x86g_dirtyhelper_loadF80le",
4633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &x86g_dirtyhelper_loadF80le,
4634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               args
4635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            );
4636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare that we're reading memory */
4637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Read;
4638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
4639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 10;
4640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* execute the dirty call, dumping the result in val. */
4642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
4643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldt %s\n", dis_buf);
4647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: { /* FSTP extended-real */
4651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
4652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr** args
4653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  = mkIRExprVec_2( mkexpr(addr),
4654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   unop(Iop_ReinterpF64asI64, get_ST(0)) );
4655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d = unsafeIRDirty_0_N (
4657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               0/*regparms*/,
4658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "x86g_dirtyhelper_storeF80le",
4659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &x86g_dirtyhelper_storeF80le,
4660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               args
4661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            );
4662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing memory */
4663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Write;
4664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
4665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 10;
4666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* execute the dirty call. */
4668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
4669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstpt\n %s", dis_buf);
4672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDB\n");
4678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
4682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
4684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
4685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
4687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC0;
4688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovnb %%st(%d), %%st(0)\n", (Int)r_src);
4689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Mux0X(
4691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_1Uto8,
4692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mk_x86g_calculate_condition(X86CondNB)),
4693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    get_ST(0), get_ST(r_src)) );
4694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC8;
4698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovnz %%st(%d), %%st(0)\n", (Int)r_src);
4699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Mux0X(
4701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_1Uto8,
4702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mk_x86g_calculate_condition(X86CondNZ)),
4703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    get_ST(0), get_ST(r_src)) );
4704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
4707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xD0;
4708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovnbe %%st(%d), %%st(0)\n", (Int)r_src);
4709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Mux0X(
4711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_1Uto8,
4712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mk_x86g_calculate_condition(X86CondNBE)),
4713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    get_ST(0), get_ST(r_src)) );
4714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
4717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xD8;
4718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovnu %%st(%d), %%st(0)\n", (Int)r_src);
4719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Mux0X(
4721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_1Uto8,
4722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mk_x86g_calculate_condition(X86CondNP)),
4723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    get_ST(0), get_ST(r_src)) );
4724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE2:
4727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnclex\n");
4728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE3: {
4731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
4732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     void x86g_do_FINIT ( VexGuestX86State* ) */
4733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d  = unsafeIRDirty_0_N (
4734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                0/*regparms*/,
4735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                "x86g_dirtyhelper_FINIT",
4736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                &x86g_dirtyhelper_FINIT,
4737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkIRExprVec_0()
4738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             );
4739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->needsBBP = True;
4740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing guest state */
4742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->nFxState = 5;
4743663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               vex_bzero(&d->fxState, sizeof(d->fxState));
4744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].fx     = Ifx_Write;
4746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].offset = OFFB_FTOP;
4747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].size   = sizeof(UInt);
4748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].fx     = Ifx_Write;
4750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].offset = OFFB_FPREGS;
4751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].size   = 8 * sizeof(ULong);
4752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].fx     = Ifx_Write;
4754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].offset = OFFB_FPTAGS;
4755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].size   = 8 * sizeof(UChar);
4756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].fx     = Ifx_Write;
4758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].offset = OFFB_FPROUND;
4759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].size   = sizeof(UInt);
4760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].fx     = Ifx_Write;
4762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].offset = OFFB_FC3210;
4763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].size   = sizeof(UInt);
4764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
4766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fninit\n");
4768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
4787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDC) {
4788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
4789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
4791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
4792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
4794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
4796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FADD double-real */
4798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FMUL double-real */
4802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FCOM double-real */
4806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcoml %s\n", dis_buf);
4807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
4810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
4811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
4812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
4813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      loadLE(Ity_F64,mkexpr(addr))),
4814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
4815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
4816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
4817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FCOMP double-real */
4820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcompl %s\n", dis_buf);
4821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
4824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
4825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
4826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
4827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      loadLE(Ity_F64,mkexpr(addr))),
4828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
4829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
4830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
4831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: /* FSUB double-real */
4835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FSUBR double-real */
4839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: /* FDIV double-real */
4843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FDIVR double-real */
4847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDC\n");
4853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
4857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
4859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
4860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
4893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
4894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDD) {
4895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
4897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
4899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
4900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
4902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
4904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FLD double-real */
4906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldl %s\n", dis_buf);
4907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
4909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FISTTPQ m64 (SSE3) */
4912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistppll %s\n", dis_buf);
4913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
4914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI64S, mkU32(Irrm_ZERO), get_ST(0)) );
4915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FST double-real */
4919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstl %s\n", dis_buf);
4920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr), get_ST(0));
4921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FSTP double-real */
4924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstpl %s\n", dis_buf);
4925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr), get_ST(0));
4926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: { /* FRSTOR m108 */
4930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
4931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
4932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp   ew = newTemp(Ity_I32);
4933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d  = unsafeIRDirty_0_N (
4934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                0/*regparms*/,
4935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                "x86g_dirtyhelper_FRSTOR",
4936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                &x86g_dirtyhelper_FRSTOR,
4937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkIRExprVec_1( mkexpr(addr) )
4938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             );
4939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->needsBBP = True;
4940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->tmp      = ew;
4941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're reading memory */
4942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Read;
4943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
4944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 108;
4945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing guest state */
4947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->nFxState = 5;
4948663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               vex_bzero(&d->fxState, sizeof(d->fxState));
4949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].fx     = Ifx_Write;
4951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].offset = OFFB_FTOP;
4952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].size   = sizeof(UInt);
4953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].fx     = Ifx_Write;
4955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].offset = OFFB_FPREGS;
4956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].size   = 8 * sizeof(ULong);
4957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].fx     = Ifx_Write;
4959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].offset = OFFB_FPTAGS;
4960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].size   = 8 * sizeof(UChar);
4961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].fx     = Ifx_Write;
4963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].offset = OFFB_FPROUND;
4964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].size   = sizeof(UInt);
4965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].fx     = Ifx_Write;
4967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].offset = OFFB_FC3210;
4968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].size   = sizeof(UInt);
4969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
4971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* ew contains any emulation warning we may need to
4973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  issue.  If needed, side-exit to the next insn,
4974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  reporting the warning, so that Valgrind's dispatcher
4975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  sees the warning. */
4976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_emwarn( mkexpr(ew) );
4977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt(
4978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRStmt_Exit(
4979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_EmWarn,
4981663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
4982663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     OFFB_EIP
4983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
4984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
4985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("frstor %s\n", dis_buf);
4987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: { /* FNSAVE m108 */
4991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
4992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
4993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d = unsafeIRDirty_0_N (
4994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               0/*regparms*/,
4995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "x86g_dirtyhelper_FSAVE",
4996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &x86g_dirtyhelper_FSAVE,
4997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkIRExprVec_1( mkexpr(addr) )
4998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            );
4999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->needsBBP = True;
5000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing memory */
5001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Write;
5002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
5003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 108;
5004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're reading guest state */
5006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->nFxState = 5;
5007663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               vex_bzero(&d->fxState, sizeof(d->fxState));
5008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].fx     = Ifx_Read;
5010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].offset = OFFB_FTOP;
5011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].size   = sizeof(UInt);
5012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].fx     = Ifx_Read;
5014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].offset = OFFB_FPREGS;
5015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].size   = 8 * sizeof(ULong);
5016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].fx     = Ifx_Read;
5018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].offset = OFFB_FPTAGS;
5019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].size   = 8 * sizeof(UChar);
5020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].fx     = Ifx_Read;
5022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].offset = OFFB_FPROUND;
5023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].size   = sizeof(UInt);
5024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].fx     = Ifx_Read;
5026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].offset = OFFB_FC3210;
5027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].size   = sizeof(UInt);
5028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
5030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnsave %s\n", dis_buf);
5032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: { /* FNSTSW m16 */
5036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr* sw = get_FPU_sw();
5037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(typeOfIRExpr(irsb->tyenv, sw) == Ity_I16);
5038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), sw );
5039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnstsw %s\n", dis_buf);
5040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDD\n");
5046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
5050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
5051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FFREE %st(?) */
5053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xC0;
5054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ffree %%st(%d)\n", (Int)r_dst);
5055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_TAG ( r_dst, mkU8(0) );
5056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
5059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xD0;
5060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fst %%st(0),%%st(%d)\n", (Int)r_dst);
5061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* P4 manual says: "If the destination operand is a
5062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  non-empty register, the invalid-operation exception
5063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  is not generated.  Hence put_ST_UNCHECKED. */
5064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(r_dst, get_ST(0));
5065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xD8;
5069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstp %%st(0),%%st(%d)\n", (Int)r_dst);
5070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* P4 manual says: "If the destination operand is a
5071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  non-empty register, the invalid-operation exception
5072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  is not generated.  Hence put_ST_UNCHECKED. */
5073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(r_dst, get_ST(0));
5074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xE0;
5079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fucom %%st(0),%%st(%d)\n", (Int)r_dst);
5080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
5081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
5083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
5084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
5086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
5087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
5088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xE8;
5092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fucomp %%st(0),%%st(%d)\n", (Int)r_dst);
5093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
5094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
5096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
5097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
5099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
5100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
5101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
5112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDE) {
5113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
5115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
5117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
5118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   fop;
5119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
5121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
5123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FIADD m16int */ /* ST(0) += m16int */
5125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fiaddw %s\n", dis_buf);
5126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_AddF64;
5127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m16;
5128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
5130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fimulw %s\n", dis_buf);
5131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_MulF64;
5132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m16;
5133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FICOM m16int */
5135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ficomw %s\n", dis_buf);
5136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
5137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
5139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
5140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
5141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
5142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      unop(Iop_I32StoF64,
5143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         unop(Iop_16Sto32,
5144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           loadLE(Ity_I16,mkexpr(addr))))),
5145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
5146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
5147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
5148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FICOMP m16int */
5151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ficompw %s\n", dis_buf);
5152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
5153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
5155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
5156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
5157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
5158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      unop(Iop_I32StoF64,
5159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         unop(Iop_16Sto32,
5160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              loadLE(Ity_I16,mkexpr(addr))))),
5161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
5162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
5163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
5164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: /* FISUB m16int */ /* ST(0) -= m16int */
5168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubw %s\n", dis_buf);
5169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_SubF64;
5170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m16;
5171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
5173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubrw %s\n", dis_buf);
5174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_SubF64;
5175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_foprev_m16;
5176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
5178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubw %s\n", dis_buf);
5179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_DivF64;
5180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m16;
5181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
5183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fidivrw %s\n", dis_buf);
5184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_DivF64;
5185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_foprev_m16;
5186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do_fop_m16:
5188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(fop,
5190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0),
5192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_I32StoF64,
5193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_16Sto32,
5194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  loadLE(Ity_I16, mkexpr(addr))))));
5195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do_foprev_m16:
5198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(fop,
5200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_I32StoF64,
5202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_16Sto32,
5203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  loadLE(Ity_I16, mkexpr(addr)))),
5204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
5205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDE\n");
5210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
5216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
5217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD9: /* FCOMPP %st(0),%st(1) */
5227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fuompp %%st(0),%%st(1)\n");
5228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
5229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
5231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
5232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
5234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
5235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
5236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0,  modrm - 0xE0, True );
5242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
5245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "sub", Iop_SubF64, 0,  modrm - 0xE8, True );
5246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
5265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDF) {
5266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
5268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
5270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
5271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
5273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
5275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FILD m16int */
5277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fildw %s\n", dis_buf);
5278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, unop(Iop_I32StoF64,
5280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_16Sto32,
5281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   loadLE(Ity_I16, mkexpr(addr)))));
5282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FISTTPS m16 (SSE3) */
5285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisttps %s\n", dis_buf);
5286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
5287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI16S, mkU32(Irrm_ZERO), get_ST(0)) );
5288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FIST m16 */
5292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistp %s\n", dis_buf);
5293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
5294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
5295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FISTP m16 */
5298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistps %s\n", dis_buf);
5299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
5300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
5301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FILD m64 */
5305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fildll %s\n", dis_buf);
5306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, binop(Iop_I64StoF64,
5308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               get_roundingmode(),
5309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               loadLE(Ity_I64, mkexpr(addr))));
5310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FISTP m64 */
5313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistpll %s\n", dis_buf);
5314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
5315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI64S, get_roundingmode(), get_ST(0)) );
5316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDF\n");
5322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
5328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
5329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0: /* FFREEP %st(0) */
5331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ffreep %%st(%d)\n", 0);
5332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_TAG ( 0, mkU8(0) );
5333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0: /* FNSTSW %ax */
5337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnstsw %%ax\n");
5338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Get the FPU status word value and dump it in %AX. */
5339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0) {
5340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* The obvious thing to do is simply dump the 16-bit
5341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     status word value in %AX.  However, due to a
5342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     limitation in Memcheck's origin tracking
5343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     machinery, this causes Memcheck not to track the
5344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     origin of any undefinedness into %AH (only into
5345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     %AL/%AX/%EAX), which means origins are lost in
5346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     the sequence "fnstsw %ax; test $M,%ah; jcond .." */
5347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putIReg(2, R_EAX, get_FPU_sw());
5348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
5349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* So a somewhat lame kludge is to make it very
5350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     clear to Memcheck that the value is written to
5351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     both %AH and %AL.  This generates marginally
5352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     worse code, but I don't think it matters much. */
5353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRTemp t16 = newTemp(Ity_I16);
5354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(t16, get_FPU_sw());
5355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putIReg( 1, R_AL, unop(Iop_16to8, mkexpr(t16)) );
5356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putIReg( 1, R_AH, unop(Iop_16HIto8, mkexpr(t16)) );
5357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
5358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
5361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
5362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* not really right since COMIP != UCOMIP */
5366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
5377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("dis_FPU(x86): invalid primary opcode");
5378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_ok = True;
5380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
5381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_fail:
5383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_ok = False;
5384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
5385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
5389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
5390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- MMX INSTRUCTIONS                                     ---*/
5391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
5392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
5393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Effect of MMX insns on x87 FPU state (table 11-2 of
5395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IA32 arch manual, volume 3):
5396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Read from, or write to MMX register (viz, any insn except EMMS):
5398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FP stack pointer set to zero
5400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   EMMS:
5402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FP stack pointer set to zero
5404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
5405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void do_MMX_preamble ( void )
5407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int         i;
5409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     zero  = mkU32(0);
5411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     tag1  = mkU8(1);
5412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ftop(zero);
5413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < 8; i++)
5414663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      stmt( IRStmt_PutI( mkIRPutI(descr, zero, i, tag1) ) );
5415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void do_EMMS_preamble ( void )
5418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int         i;
5420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     zero  = mkU32(0);
5422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     tag0  = mkU8(0);
5423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ftop(zero);
5424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < 8; i++)
5425663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      stmt( IRStmt_PutI( mkIRPutI(descr, zero, i, tag0) ) );
5426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getMMXReg ( UInt archreg )
5430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg < 8);
5432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putMMXReg ( UInt archreg, IRExpr* e )
5437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg < 8);
5439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
5440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for non-shift MMX insns.  Note this is incomplete in the
5445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sense that it does not first call do_MMX_preamble() -- that is the
5446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   responsibility of its caller. */
5447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
5449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_MMXop_regmem_to_reg ( UChar  sorb,
5450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               Int    delta,
5451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               UChar  opc,
5452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               HChar* name,
5453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               Bool   show_granularity )
5454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
5456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   modrm = getIByte(delta);
5457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    isReg = epartIsReg(modrm);
5458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* argL  = NULL;
5459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* argR  = NULL;
5460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* argG  = NULL;
5461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* argE  = NULL;
5462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  res   = newTemp(Ity_I64);
5463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    invG  = False;
5465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    op    = Iop_INVALID;
5466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void*   hAddr = NULL;
5467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar*  hName = NULL;
5468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    eLeft = False;
5469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
5471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (opc) {
5473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Original MMX ones */
5474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFC: op = Iop_Add8x8; break;
5475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFD: op = Iop_Add16x4; break;
5476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFE: op = Iop_Add32x2; break;
5477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEC: op = Iop_QAdd8Sx8; break;
5479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xED: op = Iop_QAdd16Sx4; break;
5480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDC: op = Iop_QAdd8Ux8; break;
5482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDD: op = Iop_QAdd16Ux4; break;
5483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF8: op = Iop_Sub8x8;  break;
5485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF9: op = Iop_Sub16x4; break;
5486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFA: op = Iop_Sub32x2; break;
5487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE8: op = Iop_QSub8Sx8; break;
5489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE9: op = Iop_QSub16Sx4; break;
5490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD8: op = Iop_QSub8Ux8; break;
5492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD9: op = Iop_QSub16Ux4; break;
5493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE5: op = Iop_MulHi16Sx4; break;
5495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD5: op = Iop_Mul16x4; break;
5496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
5497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x74: op = Iop_CmpEQ8x8; break;
5499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x75: op = Iop_CmpEQ16x4; break;
5500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x76: op = Iop_CmpEQ32x2; break;
5501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x64: op = Iop_CmpGT8Sx8; break;
5503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x65: op = Iop_CmpGT16Sx4; break;
5504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x66: op = Iop_CmpGT32Sx2; break;
5505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5506b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case 0x6B: op = Iop_QNarrowBin32Sto16Sx4; eLeft = True; break;
5507b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case 0x63: op = Iop_QNarrowBin16Sto8Sx8;  eLeft = True; break;
5508b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case 0x67: op = Iop_QNarrowBin16Sto8Ux8;  eLeft = True; break;
5509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x68: op = Iop_InterleaveHI8x8;  eLeft = True; break;
5511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
5512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
5513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x60: op = Iop_InterleaveLO8x8;  eLeft = True; break;
5515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
5516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
5517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDB: op = Iop_And64; break;
5519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDF: op = Iop_And64; invG = True; break;
5520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEB: op = Iop_Or64; break;
5521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEF: /* Possibly do better here if argL and argR are the
5522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    same reg */
5523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 op = Iop_Xor64; break;
5524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Introduced in SSE1 */
5526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE0: op = Iop_Avg8Ux8;    break;
5527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE3: op = Iop_Avg16Ux4;   break;
5528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEE: op = Iop_Max16Sx4;   break;
5529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDE: op = Iop_Max8Ux8;    break;
5530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEA: op = Iop_Min16Sx4;   break;
5531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDA: op = Iop_Min8Ux8;    break;
5532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE4: op = Iop_MulHi16Ux4; break;
5533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
5534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Introduced in SSE2 */
5536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD4: op = Iop_Add64; break;
5537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFB: op = Iop_Sub64; break;
5538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
5540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("\n0x%x\n", (Int)opc);
5541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("dis_MMXop_regmem_to_reg");
5542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef XXX
5545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   argG = getMMXReg(gregOfRM(modrm));
5547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (invG)
5548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argG = unop(Iop_Not64, argG);
5549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isReg) {
5551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
5552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argE = getMMXReg(eregOfRM(modrm));
5553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
5554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    len;
5555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
5557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argE = loadLE(Ity_I64, mkexpr(addr));
5558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (eLeft) {
5561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argL = argE;
5562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argR = argG;
5563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
5564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argL = argG;
5565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argR = argE;
5566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op != Iop_INVALID) {
5569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(hName == NULL);
5570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(hAddr == NULL);
5571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(op, argL, argR));
5572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
5573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(hName != NULL);
5574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(hAddr != NULL);
5575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( res,
5576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              mkIRExprCCall(
5577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Ity_I64,
5578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 0/*regparms*/, hName, hAddr,
5579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkIRExprVec_2( argL, argR )
5580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
5581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
5582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putMMXReg( gregOfRM(modrm), mkexpr(res) );
5585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%s %s, %s\n",
5587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       name, show_granularity ? nameMMXGran(opc & 3) : "",
5588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameMMXReg(gregOfRM(modrm)) );
5590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
5592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vector by scalar shift of G by the amount specified at the bottom
5596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of E.  This is a straight copy of dis_SSE_shiftG_byE. */
5597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_MMX_shiftG_byE ( UChar sorb, Int delta,
5599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 HChar* opname, IROp op )
5600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
5602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen, size;
5603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
5604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    shl, shr, sar;
5605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getIByte(delta);
5606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  g0   = newTemp(Ity_I64);
5607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  g1   = newTemp(Ity_I64);
5608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  amt  = newTemp(Ity_I32);
5609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  amt8 = newTemp(Ity_I8);
5610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
5612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
5613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
5614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameMMXReg(eregOfRM(rm)),
5615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameMMXReg(gregOfRM(rm)) );
5616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
5617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
5618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
5619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
5620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
5621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
5622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameMMXReg(gregOfRM(rm)) );
5623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
5624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( g0,   getMMXReg(gregOfRM(rm)) );
5626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
5627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shl = shr = sar = False;
5629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   size = 0;
5630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
5631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN16x4: shl = True; size = 32; break;
5632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN32x2: shl = True; size = 32; break;
5633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shl64:    shl = True; size = 64; break;
5634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN16x4: shr = True; size = 16; break;
5635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN32x2: shr = True; size = 32; break;
5636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shr64:    shr = True; size = 64; break;
5637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN16x4: sar = True; size = 16; break;
5638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN32x2: sar = True; size = 32; break;
5639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
5640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shl || shr) {
5643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(
5644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        g1,
5645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr_Mux0X(
5646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           mkU64(0),
5648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(op, mkexpr(g0), mkexpr(amt8))
5649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
5650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
5651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else
5652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sar) {
5653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(
5654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        g1,
5655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr_Mux0X(
5656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(op, mkexpr(g0), mkU8(size-1)),
5658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(op, mkexpr(g0), mkexpr(amt8))
5659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
5660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
5661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
5662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
5663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0);
5664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putMMXReg( gregOfRM(rm), mkexpr(g1) );
5667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
5668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vector by scalar shift of E by an immediate byte.  This is a
5672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   straight copy of dis_SSE_shiftE_imm. */
5673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
5675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_MMX_shiftE_imm ( Int delta, HChar* opname, IROp op )
5676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    shl, shr, sar;
5678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getIByte(delta);
5679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  e0   = newTemp(Ity_I64);
5680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  e1   = newTemp(Ity_I64);
5681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   amt, size;
5682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(epartIsReg(rm));
5683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(gregOfRM(rm) == 2
5684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
5685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   amt = getIByte(delta+1);
5686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta += 2;
5687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s $%d,%s\n", opname,
5688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      (Int)amt,
5689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameMMXReg(eregOfRM(rm)) );
5690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( e0, getMMXReg(eregOfRM(rm)) );
5692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shl = shr = sar = False;
5694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   size = 0;
5695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
5696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN16x4: shl = True; size = 16; break;
5697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN32x2: shl = True; size = 32; break;
5698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shl64:    shl = True; size = 64; break;
5699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN16x4: sar = True; size = 16; break;
5700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN32x2: sar = True; size = 32; break;
5701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN16x4: shr = True; size = 16; break;
5702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN32x2: shr = True; size = 32; break;
5703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shr64:    shr = True; size = 64; break;
5704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
5705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shl || shr) {
5708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e1, amt >= size
5709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ? mkU64(0)
5710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : binop(op, mkexpr(e0), mkU8(amt))
5711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
5712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else
5713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sar) {
5714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e1, amt >= size
5715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ? binop(op, mkexpr(e0), mkU8(size-1))
5716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : binop(op, mkexpr(e0), mkU8(amt))
5717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
5718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
5719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
5720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0);
5721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putMMXReg( eregOfRM(rm), mkexpr(e1) );
5724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
5725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Completely handle all MMX instructions except emms. */
5729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
5731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, Int delta )
5732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   len;
5734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar modrm;
5735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
5736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar opc = getIByte(delta);
5737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta++;
5738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* dis_MMX handles all insns except emms. */
5740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_MMX_preamble();
5741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (opc) {
5743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6E:
5745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
5746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
5749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
5750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
5751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putMMXReg(
5752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               gregOfRM(modrm),
5753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop( Iop_32HLto64,
5754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(0),
5755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      getIReg(4, eregOfRM(modrm)) ) );
5756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movd %s, %s\n",
5757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
5759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += len;
5761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putMMXReg(
5762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               gregOfRM(modrm),
5763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop( Iop_32HLto64,
5764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(0),
5765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      loadLE(Ity_I32, mkexpr(addr)) ) );
5766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
5767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
5771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
5774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
5775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
5776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg( 4, eregOfRM(modrm),
5777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movd %s, %s\n",
5779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
5780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
5781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += len;
5783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(addr),
5784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
5786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6F:
5790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
5791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
5794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
5795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
5796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movq %s, %s\n",
5798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
5800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += len;
5802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movq %s, %s\n",
5804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                dis_buf, nameMMXReg(gregOfRM(modrm)));
5805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x7F:
5809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
5810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
5813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
5814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
5815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putMMXReg( eregOfRM(modrm), getMMXReg(gregOfRM(modrm)) );
5816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movq %s, %s\n",
5817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
5818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
5819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += len;
5821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
5822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("mov(nt)q %s, %s\n",
5823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameMMXReg(gregOfRM(modrm)), dis_buf);
5824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFC:
5828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFD:
5829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
5830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEC:
5836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
5837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDC:
5843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
5844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF8:
5850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF9:
5851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
5852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
5855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE8:
5858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
5859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD8:
5865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
5866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
5872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
5878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
5884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(sz == 4);
5885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
5886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x74:
5889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x75:
5890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
5891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
5894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x64:
5897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x65:
5898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
5899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
5902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
5905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
5908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
5911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
5914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
5917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
5920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x68:
5923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x69:
5924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
5925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
5928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x60:
5931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x61:
5932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
5933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
5936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
5939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
5942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
5945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
5948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
5951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
5954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
5957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
5960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SHIFT_BY_REG(_name,_op)                                 \
5963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
5964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                break;
5965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
5967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
5968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
5969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
5970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
5972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
5973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
5974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
5975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
5977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
5978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
5979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SHIFT_BY_REG
5981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x71:
5983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x72:
5984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x73: {
5985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
5986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar byte2, subopc;
5987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         byte2  = getIByte(delta);           /* amode / sub-opcode */
5990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         subopc = toUChar( (byte2 >> 3) & 7 );
5991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        define SHIFT_BY_IMM(_name,_op)                         \
5993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             do { delta = dis_MMX_shiftE_imm(delta,_name,_op);  \
5994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             } while (0)
5995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              if (subopc == 2 /*SRL*/ && opc == 0x71)
5997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
5998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 2 /*SRL*/ && opc == 0x72)
5999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
6000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 2 /*SRL*/ && opc == 0x73)
6001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psrlq", Iop_Shr64);
6002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 4 /*SAR*/ && opc == 0x71)
6004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
6005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 4 /*SAR*/ && opc == 0x72)
6006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
6007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 6 /*SHL*/ && opc == 0x71)
6009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
6010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 6 /*SHL*/ && opc == 0x72)
6011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
6012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 6 /*SHL*/ && opc == 0x73)
6013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psllq", Iop_Shl64);
6014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else goto mmx_decode_failure;
6016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        undef SHIFT_BY_IMM
6018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
6020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF7: {
6022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr    = newTemp(Ity_I32);
6023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp regD    = newTemp(Ity_I64);
6024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp regM    = newTemp(Ity_I64);
6025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp mask    = newTemp(Ity_I64);
6026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp olddata = newTemp(Ity_I64);
6027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp newdata = newTemp(Ity_I64);
6028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
6030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4 || (!epartIsReg(modrm)))
6031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
6033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
6035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( regM, getMMXReg( eregOfRM(modrm) ));
6036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( regD, getMMXReg( gregOfRM(modrm) ));
6037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( mask, binop(Iop_SarN8x8, mkexpr(regM), mkU8(7)) );
6038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( olddata, loadLE( Ity_I64, mkexpr(addr) ));
6039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( newdata,
6040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Or64,
6041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And64,
6042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(regD),
6043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(mask) ),
6044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And64,
6045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(olddata),
6046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_Not64, mkexpr(mask)))) );
6047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), mkexpr(newdata) );
6048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("maskmovq %s,%s\n", nameMMXReg( eregOfRM(modrm) ),
6049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameMMXReg( gregOfRM(modrm) ) );
6050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
6052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* --- MMX decode failure --- */
6054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
6055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mmx_decode_failure:
6056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *decode_ok = False;
6057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return delta; /* ignored */
6058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_ok = True;
6062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
6063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
6067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- More misc arithmetic and other obscure insns.        ---*/
6068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
6069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Double length left and right shifts.  Apparently only required in
6071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v-size (no b- variant). */
6072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_SHLRD_Gv_Ev ( UChar sorb,
6074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Int delta, UChar modrm,
6075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Int sz,
6076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr* shift_amt,
6077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Bool amt_is_literal,
6078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       HChar* shift_amt_txt,
6079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Bool left_shift )
6080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* shift_amt :: Ity_I8 is the amount to shift.  shift_amt_txt is used
6082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for printing it.   And eip on entry points at the modrm byte. */
6083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int len;
6084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
6085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty       = szToITy(sz);
6087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp gsrc     = newTemp(ty);
6088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp esrc     = newTemp(ty);
6089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp addr     = IRTemp_INVALID;
6090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpSH    = newTemp(Ity_I8);
6091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpL     = IRTemp_INVALID;
6092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpRes   = IRTemp_INVALID;
6093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpSubSh = IRTemp_INVALID;
6094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   mkpair;
6095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   getres;
6096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   shift;
6097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* mask = NULL;
6098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 2 || sz == 4);
6100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The E-part is the destination; this is shifted.  The G-part
6102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      supplies bits to be shifted into the E-part, but is not
6103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      changed.
6104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If shifting left, form a double-length word with E at the top
6106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      and G at the bottom, and shift this left.  The result is then in
6107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the high part.
6108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If shifting right, form a double-length word with G at the top
6110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      and E at the bottom, and shift this right.  The result is then
6111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      at the bottom.  */
6112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Fetch the operands. */
6114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
6116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
6118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
6119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( esrc, getIReg(sz, eregOfRM(modrm)) );
6120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sh%cd%c %s, %s, %s\n",
6121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ( left_shift ? 'l' : 'r' ), nameISize(sz),
6122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          shift_amt_txt,
6123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
6124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta, dis_buf );
6126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
6127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( esrc, loadLE(ty, mkexpr(addr)) );
6128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sh%cd%c %s, %s, %s\n",
6129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ( left_shift ? 'l' : 'r' ), nameISize(sz),
6130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          shift_amt_txt,
6131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameIReg(sz, gregOfRM(modrm)), dis_buf);
6132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Round up the relevant primops. */
6135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4) {
6137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpL     = newTemp(Ity_I64);
6138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpRes   = newTemp(Ity_I32);
6139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpSubSh = newTemp(Ity_I32);
6140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mkpair   = Iop_32HLto64;
6141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      getres   = left_shift ? Iop_64HIto32 : Iop_64to32;
6142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      shift    = left_shift ? Iop_Shl64 : Iop_Shr64;
6143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mask     = mkU8(31);
6144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* sz == 2 */
6146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpL     = newTemp(Ity_I32);
6147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpRes   = newTemp(Ity_I16);
6148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpSubSh = newTemp(Ity_I16);
6149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mkpair   = Iop_16HLto32;
6150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      getres   = left_shift ? Iop_32HIto16 : Iop_32to16;
6151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      shift    = left_shift ? Iop_Shl32 : Iop_Shr32;
6152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mask     = mkU8(15);
6153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Do the shift, calculate the subshift value, and set
6156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the flag thunk. */
6157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
6159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (left_shift)
6161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
6162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
6163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
6164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
6166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tmpSubSh,
6167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(getres,
6168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(shift,
6169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(tmpL),
6170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And8,
6171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mask))) );
6173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
6175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              tmpRes, tmpSubSh, ty, tmpSH );
6176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Put result back. */
6178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
6180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
6181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), mkexpr(tmpRes) );
6183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (amt_is_literal) delta++;
6186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
6187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle BT/BTS/BTR/BTC Gv, Ev.  Apparently b-size is not
6191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   required. */
6192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
6194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameBtOp ( BtOp op )
6196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
6198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case BtOpNone:  return "";
6199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case BtOpSet:   return "s";
6200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case BtOpReset: return "r";
6201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case BtOpComp:  return "c";
6202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameBtOp(x86)");
6203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_bt_G_E ( VexAbiInfo* vbi,
6209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  UChar sorb, Bool locked, Int sz, Int delta, BtOp op )
6210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
6212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  modrm;
6213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    len;
6214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
6215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          t_addr1, t_esp, t_mask, t_new;
6216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 2 || sz == 4);
6218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_fetched = t_bitno0 = t_bitno1 = t_bitno2
6220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             = t_addr0 = t_addr1 = t_esp
6221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             = t_mask = t_new = IRTemp_INVALID;
6222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_fetched = newTemp(Ity_I8);
6224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_new     = newTemp(Ity_I8);
6225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_bitno0  = newTemp(Ity_I32);
6226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_bitno1  = newTemp(Ity_I32);
6227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_bitno2  = newTemp(Ity_I8);
6228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_addr1   = newTemp(Ity_I32);
6229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm     = getIByte(delta);
6230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t_bitno0, widenSto32(getIReg(sz, gregOfRM(modrm))) );
6232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
6234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
6235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Get it onto the client's stack. */
6236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_esp = newTemp(Ity_I32);
6237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_addr0 = newTemp(Ity_I32);
6238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* For the choice of the value 128, see comment in dis_bt_G_E in
6240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         guest_amd64_toIR.c.  We point out here only that 128 is
6241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         fast-cased in Memcheck and is > 0, so seems like a good
6242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         choice. */
6243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(vbi->guest_stack_redzone_size == 0);
6244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(128)) );
6245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, mkexpr(t_esp));
6246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
6248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Make t_addr0 point at it. */
6250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_addr0, mkexpr(t_esp) );
6251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Mask out upper bits of the shift amount, since we're doing a
6253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         reg. */
6254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_bitno1, binop(Iop_And32,
6255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(t_bitno0),
6256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(sz == 4 ? 31 : 15)) );
6257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
6260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
6261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_bitno1, mkexpr(t_bitno0) );
6262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* At this point: t_addr0 is the address being operated on.  If it
6265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      was a reg, we will have pushed it onto the client's stack.
6266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_bitno1 is the bit number, suitably masked in the case of a
6267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg.  */
6268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now the main sequence. */
6270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t_addr1,
6271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_Add32,
6272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkexpr(t_addr0),
6273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
6274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t_addr1 now holds effective address */
6276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t_bitno2,
6278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(Iop_32to8,
6279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
6280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t_bitno2 contains offset of bit within byte */
6282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op != BtOpNone) {
6284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_mask = newTemp(Ity_I8);
6285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
6286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t_mask is now a suitable byte mask */
6289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
6291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op != BtOpNone) {
6293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (op) {
6294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BtOpSet:
6295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t_new,
6296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Or8, mkexpr(t_fetched), mkexpr(t_mask)) );
6297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
6298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BtOpComp:
6299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t_new,
6300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Xor8, mkexpr(t_fetched), mkexpr(t_mask)) );
6301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
6302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BtOpReset:
6303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t_new,
6304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And8, mkexpr(t_fetched),
6305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_Not8, mkexpr(t_mask))) );
6306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
6307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
6308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("dis_bt_G_E(x86)");
6309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
6310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (locked && !epartIsReg(modrm)) {
6311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         casLE( mkexpr(t_addr1), mkexpr(t_fetched)/*expd*/,
6312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkexpr(t_new)/*new*/,
6313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 guest_EIP_curr_instr );
6314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
6315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(t_addr1), mkexpr(t_new) );
6316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
6317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Side effect done; now get selected bit into Carry flag */
6320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
6321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
6322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
6324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_CC_DEP1,
6325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And32,
6326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Shr32,
6327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_8Uto32, mkexpr(t_fetched)),
6328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(t_bitno2)),
6329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU32(1)))
6330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       );
6331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
6332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
6333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
6334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Move reg operand from stack back to reg */
6336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
6337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t_esp still points at it. */
6338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
6339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(128)) );
6340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("bt%s%c %s, %s\n",
6343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
6344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
6345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
6347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle BSF/BSR.  Only v-size seems necessary. */
6352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_bs_E_G ( UChar sorb, Int sz, Int delta, Bool fwds )
6354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   isReg;
6356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  modrm;
6357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
6358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty  = szToITy(sz);
6360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src = newTemp(ty);
6361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst = newTemp(ty);
6362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src32 = newTemp(Ity_I32);
6364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst32 = newTemp(Ity_I32);
6365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src8  = newTemp(Ity_I8);
6366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 4 || sz == 2);
6368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm = getIByte(delta);
6370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   isReg = epartIsReg(modrm);
6372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isReg) {
6373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
6374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, getIReg(sz, eregOfRM(modrm)) );
6375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    len;
6377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
6379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, loadLE(ty, mkexpr(addr)) );
6380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("bs%c%c %s, %s\n",
6383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       fwds ? 'f' : 'r', nameISize(sz),
6384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
6385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameIReg(sz, gregOfRM(modrm)));
6386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Generate an 8-bit expression which is zero iff the
6388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      original is zero, and nonzero otherwise */
6389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( src8,
6390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
6391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(src), mkU(ty,0))) );
6392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Flags: Z is 1 iff source value is zero.  All others
6394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      are undefined -- we force them to zero. */
6395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
6396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
6398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_CC_DEP1,
6399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr_Mux0X( mkexpr(src8),
6400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          /* src==0 */
6401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(X86G_CC_MASK_Z),
6402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          /* src!=0 */
6403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0)
6404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        )
6405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ));
6406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
6407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
6408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
6409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Result: iff source value is zero, we can't use
6411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
6412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      But anyway, Intel x86 semantics say the result is undefined in
6413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      such situations.  Hence handle the zero case specially. */
6414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Bleh.  What we compute:
6416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsf32:  if src == 0 then 0 else  Ctz32(src)
6418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsr32:  if src == 0 then 0 else  31 - Clz32(src)
6419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsf16:  if src == 0 then 0 else  Ctz32(16Uto32(src))
6421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsr16:  if src == 0 then 0 else  31 - Clz32(16Uto32(src))
6422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      First, widen src to 32 bits if it is not already.
6424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
6426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dst register unchanged when src == 0.  Hence change accordingly.
6427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
6428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2)
6429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
6430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
6431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src32, mkexpr(src) );
6432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The main computation, guarding against zero. */
6434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( dst32,
6435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           IRExpr_Mux0X(
6436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              mkexpr(src8),
6437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              /* src == 0 -- leave dst unchanged */
6438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              widenUto32( getIReg( sz, gregOfRM(modrm) ) ),
6439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              /* src != 0 */
6440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              fwds ? unop(Iop_Ctz32, mkexpr(src32))
6441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   : binop(Iop_Sub32,
6442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32(31),
6443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(Iop_Clz32, mkexpr(src32)))
6444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           )
6445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
6446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2)
6448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
6449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
6450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst, mkexpr(dst32) );
6451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* dump result back */
6453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
6454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
6456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid codegen_xchg_eAX_Reg ( Int sz, Int reg )
6461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
6463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1 = newTemp(ty);
6464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2 = newTemp(ty);
6465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 2 || sz == 4);
6466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t1, getIReg(sz, R_EAX) );
6467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t2, getIReg(sz, reg) );
6468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( sz, R_EAX, mkexpr(t2) );
6469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( sz, reg, mkexpr(t1) );
6470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("xchg%c %s, %s\n",
6471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
6472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid codegen_SAHF ( void )
6477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set the flags to:
6479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (x86g_calculate_flags_all() & X86G_CC_MASK_O)  -- retain the old O flag
6480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                |X86G_CC_MASK_P|X86G_CC_MASK_C)
6482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
6483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       |X86G_CC_MASK_C|X86G_CC_MASK_P;
6485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp oldflags   = newTemp(Ity_I32);
6486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldflags, mk_x86g_calculate_eflags_all() );
6487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
6488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
6489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1,
6491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_Or32,
6492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
6493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_And32,
6494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
6495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU32(mask_SZACP))
6496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
6497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ));
6498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
6499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
6500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
6501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid codegen_LAHF ( void  )
6506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* AH <- EFLAGS(SF:ZF:0:AF:0:PF:1:CF) */
6508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* eax_with_hole;
6509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* new_byte;
6510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* new_eax;
6511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt    mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        |X86G_CC_MASK_C|X86G_CC_MASK_P;
6513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  flags = newTemp(Ity_I32);
6515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( flags, mk_x86g_calculate_eflags_all() );
6516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   eax_with_hole
6518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = binop(Iop_And32, getIReg(4, R_EAX), mkU32(0xFFFF00FF));
6519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   new_byte
6520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = binop(Iop_Or32, binop(Iop_And32, mkexpr(flags), mkU32(mask_SZACP)),
6521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32(1<<1));
6522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   new_eax
6523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = binop(Iop_Or32, eax_with_hole,
6524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl32, new_byte, mkU8(8)));
6525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(4, R_EAX, new_eax);
6526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_cmpxchg_G_E ( UChar       sorb,
6531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Bool        locked,
6532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Int         size,
6533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Int         delta0 )
6534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
6536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   len;
6537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty    = szToITy(size);
6539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp acc   = newTemp(ty);
6540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src   = newTemp(ty);
6541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dest  = newTemp(ty);
6542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dest2 = newTemp(ty);
6543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp acc2  = newTemp(ty);
6544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp cond8 = newTemp(Ity_I8);
6545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp addr  = IRTemp_INVALID;
6546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  rm    = getUChar(delta0);
6547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* There are 3 cases to consider:
6549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-reg: ignore any lock prefix, generate sequence based
6551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               on Mux0X
6552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-mem, not locked: ignore any lock prefix, generate sequence
6554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           based on Mux0X
6555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-mem, locked: use IRCAS
6557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
6558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 1 */
6560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dest, getIReg(size, eregOfRM(rm)) );
6561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta0++;
6562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, getIReg(size, gregOfRM(rm)) );
6563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc, getIReg(size, R_EAX) );
6564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
6566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
6567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc2,  IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
6568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, R_EAX, mkexpr(acc2));
6569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, eregOfRM(rm), mkexpr(dest2));
6570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmpxchg%c %s,%s\n", nameISize(size),
6571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(size,gregOfRM(rm)),
6572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(size,eregOfRM(rm)) );
6573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (!epartIsReg(rm) && !locked) {
6575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 2 */
6576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta0, dis_buf );
6577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dest, loadLE(ty, mkexpr(addr)) );
6578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta0 += len;
6579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, getIReg(size, gregOfRM(rm)) );
6580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc, getIReg(size, R_EAX) );
6581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
6583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
6584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc2,  IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
6585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, R_EAX, mkexpr(acc2));
6586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), mkexpr(dest2) );
6587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmpxchg%c %s,%s\n", nameISize(size),
6588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(size,gregOfRM(rm)), dis_buf);
6589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (!epartIsReg(rm) && locked) {
6591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 3 */
6592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* src is new value.  acc is expected value.  dest is old value.
6593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Compute success from the output of the IRCAS, and steer the
6594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         new value for EAX accordingly: in case of success, EAX is
6595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unchanged. */
6596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta0, dis_buf );
6597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta0 += len;
6598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, getIReg(size, gregOfRM(rm)) );
6599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc, getIReg(size, R_EAX) );
6600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_CAS(
6601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkIRCAS( IRTemp_INVALID, dest, Iend_LE, mkexpr(addr),
6602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  NULL, mkexpr(acc), NULL, mkexpr(src) )
6603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ));
6604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
6606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc2,  IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
6607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, R_EAX, mkexpr(acc2));
6608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmpxchg%c %s,%s\n", nameISize(size),
6609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(size,gregOfRM(rm)), dis_buf);
6610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else vassert(0);
6612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta0;
6614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle conditional move instructions of the form
6618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cmovcc E(reg-or-mem), G(reg)
6619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(src) is reg-or-mem
6621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(dst) is reg.
6622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %E, tmps
6624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       GET %G, tmpd
6625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       CMOVcc tmps, tmpd
6626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpd, %G
6627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem  -->    (getAddr E) -> tmpa
6629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmps
6630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       GET %G, tmpd
6631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       CMOVcc tmps, tmpd
6632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpd, %G
6633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
6634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_cmov_E_G ( UChar       sorb,
6636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int         sz,
6637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    X86Condcode cond,
6638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int         delta0 )
6639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm  = getIByte(delta0);
6641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
6642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   len;
6643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty   = szToITy(sz);
6645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmps = newTemp(ty);
6646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpd = newTemp(ty);
6647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmps, getIReg(sz, eregOfRM(rm)) );
6650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(rm),
6653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRExpr_Mux0X( unop(Iop_1Uto8,
6654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     mk_x86g_calculate_condition(cond)),
6655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(tmpd),
6656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(tmps) )
6657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             );
6658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmov%c%s %s,%s\n", nameISize(sz),
6659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              name_X86Condcode(cond),
6660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameIReg(sz,eregOfRM(rm)),
6661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameIReg(sz,gregOfRM(rm)));
6662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
6663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
6666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
6667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmps, loadLE(ty, mkexpr(addr)) );
6669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(rm),
6672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRExpr_Mux0X( unop(Iop_1Uto8,
6673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     mk_x86g_calculate_condition(cond)),
6674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(tmpd),
6675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(tmps) )
6676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             );
6677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmov%c%s %s,%s\n", nameISize(sz),
6679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              name_X86Condcode(cond),
6680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              dis_buf,
6681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameIReg(sz,gregOfRM(rm)));
6682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
6683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_xadd_G_E ( UChar sorb, Bool locked, Int sz, Int delta0,
6689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool* decodeOK )
6690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   len;
6692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm = getIByte(delta0);
6693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
6694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty    = szToITy(sz);
6696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpd  = newTemp(ty);
6697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpt0 = newTemp(ty);
6698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpt1 = newTemp(ty);
6699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* There are 3 cases to consider:
6701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-reg: ignore any lock prefix,
6703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               generate 'naive' (non-atomic) sequence
6704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-mem, not locked: ignore any lock prefix, generate 'naive'
6706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (non-atomic) sequence
6707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-mem, locked: use IRCAS
6709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
6710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 1 */
6713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd,  getIReg(sz, eregOfRM(rm)));
6714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(tmpd), mkexpr(tmpt0)) );
6717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, eregOfRM(rm), mkexpr(tmpt1));
6719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("xadd%c %s, %s\n",
6721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameISize(sz), nameIReg(sz,gregOfRM(rm)),
6722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          				 nameIReg(sz,eregOfRM(rm)));
6723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decodeOK = True;
6724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
6725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (!epartIsReg(rm) && !locked) {
6727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 2 */
6728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd,  loadLE(ty, mkexpr(addr)) );
6730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(tmpd), mkexpr(tmpt0)) );
6733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), mkexpr(tmpt1) );
6734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("xadd%c %s, %s\n",
6737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decodeOK = True;
6739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
6740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (!epartIsReg(rm) && locked) {
6742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 3 */
6743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd,  loadLE(ty, mkexpr(addr)) );
6745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(tmpd), mkexpr(tmpt0)) );
6748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      casLE( mkexpr(addr), mkexpr(tmpd)/*expVal*/,
6749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(tmpt1)/*newVal*/, guest_EIP_curr_instr );
6750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("xadd%c %s, %s\n",
6753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decodeOK = True;
6755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
6756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*UNREACHED*/
6758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(0);
6759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
6762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_mov_Ew_Sw ( UChar sorb, Int delta0 )
6765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    len;
6767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp addr;
6768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  rm  = getIByte(delta0);
6769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
6770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
6773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
6774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
6775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta0, dis_buf );
6777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
6778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
6779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
6780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Move 16 bits from G (a segment register) to Ew (ireg or mem).  If
6784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dst is ireg and sz==4, zero out top half of it.  */
6785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_mov_Sw_Ew ( UChar sorb,
6788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Int   sz,
6789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Int   delta0 )
6790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    len;
6792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp addr;
6793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  rm  = getIByte(delta0);
6794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
6795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 2 || sz == 4);
6797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4)
6800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
6802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
6806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta0, dis_buf );
6808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
6809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
6810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
6811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_push_segreg ( UInt sreg, Int sz )
6817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    IRTemp t1 = newTemp(Ity_I16);
6819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    IRTemp ta = newTemp(Ity_I32);
6820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    vassert(sz == 2 || sz == 4);
6821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assign( t1, getSReg(sreg) );
6823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    putIReg(4, R_ESP, mkexpr(ta));
6825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    storeLE( mkexpr(ta), mkexpr(t1) );
6826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    DIP("push%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
6828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_pop_segreg ( UInt sreg, Int sz )
6832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    IRTemp t1 = newTemp(Ity_I16);
6834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    IRTemp ta = newTemp(Ity_I32);
6835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    vassert(sz == 2 || sz == 4);
6836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assign( ta, getIReg(4, R_ESP) );
6838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
6839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
6841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    putSReg( sreg, mkexpr(t1) );
6842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    DIP("pop%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
6843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6846663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengvoid dis_ret ( /*MOD*/DisResult* dres, UInt d32 )
6847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6848663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   IRTemp t1 = newTemp(Ity_I32);
6849663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   IRTemp t2 = newTemp(Ity_I32);
6850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(t1, getIReg(4,R_ESP));
6851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
6853663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   jmp_treg(dres, Ijk_Ret, t2);
6854663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->whatNext == Dis_StopHere);
6855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
6858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- SSE/SSE2/SSE3 helpers                                ---*/
6859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
6860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Worker function; do not call directly.
6862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Handles full width G = G `op` E   and   G = (not G) `op` E.
6863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
6864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_E_to_G_all_wrk (
6866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UChar sorb, Int delta,
6867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               HChar* opname, IROp op,
6868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Bool   invertG
6869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
6870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
6872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
6873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
6874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
6875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* gpart
6876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRM(rm)))
6877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                : getXMMReg(gregOfRM(rm));
6878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
6880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart,
6881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getXMMReg(eregOfRM(rm))) );
6882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
6883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
6884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
6885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
6886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
6888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
6889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart,
6890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           loadLE(Ity_V128, mkexpr(addr))) );
6891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
6892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
6893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
6894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
6895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* All lanes SSE binary operation, G = G `op` E. */
6900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_SSE_E_to_G_all ( UChar sorb, Int delta, HChar* opname, IROp op )
6903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
6905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* All lanes SSE binary operation, G = (not G) `op` E. */
6908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_SSE_E_to_G_all_invG ( UChar sorb, Int delta,
6911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               HChar* opname, IROp op )
6912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
6914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
6918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_E_to_G_lo32 ( UChar sorb, Int delta,
6920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  HChar* opname, IROp op )
6921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
6923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
6924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
6925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
6926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* gpart = getXMMReg(gregOfRM(rm));
6927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
6929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart,
6930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getXMMReg(eregOfRM(rm))) );
6931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
6932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
6933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
6934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
6935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We can only do a 32-bit memory read, so the upper 3/4 of the
6937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         E operand needs to be made simply of zeroes. */
6938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp epart = newTemp(Ity_V128);
6939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
6940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( epart, unop( Iop_32UtoV128,
6941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           loadLE(Ity_I32, mkexpr(addr))) );
6942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
6943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart, mkexpr(epart)) );
6944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
6945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
6946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
6947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
6948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
6953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_E_to_G_lo64 ( UChar sorb, Int delta,
6955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  HChar* opname, IROp op )
6956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
6958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
6959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
6960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
6961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* gpart = getXMMReg(gregOfRM(rm));
6962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
6964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart,
6965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getXMMReg(eregOfRM(rm))) );
6966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
6967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
6968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
6969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
6970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We can only do a 64-bit memory read, so the upper half of the
6972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         E operand needs to be made simply of zeroes. */
6973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp epart = newTemp(Ity_V128);
6974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
6975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( epart, unop( Iop_64UtoV128,
6976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           loadLE(Ity_I64, mkexpr(addr))) );
6977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
6978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart, mkexpr(epart)) );
6979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
6980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
6981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
6982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
6983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* All lanes unary SSE operation, G = op(E). */
6988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_E_to_G_unary_all (
6990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UChar sorb, Int delta,
6991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               HChar* opname, IROp op
6992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
6993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
6995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
6996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
6997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
6998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
7000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop(op, getXMMReg(eregOfRM(rm))) );
7001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
7003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
7005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
7007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
7008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
7009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
7011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
7013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
7018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_E_to_G_unary_lo32 (
7020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UChar sorb, Int delta,
7021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               HChar* opname, IROp op
7022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
7023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First we need to get the old G value and patch the low 32 bits
7025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of the E operand into it.  Then apply op and write back to G. */
7026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
7027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
7028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
7030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldG0 = newTemp(Ity_V128);
7031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldG1 = newTemp(Ity_V128);
7032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldG0, getXMMReg(gregOfRM(rm)) );
7034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldG1,
7037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop( Iop_SetV128lo32,
7038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(oldG0),
7039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     getXMMRegLane32(eregOfRM(rm), 0)) );
7040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
7043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
7045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
7047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldG1,
7048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop( Iop_SetV128lo32,
7049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(oldG0),
7050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     loadLE(Ity_I32, mkexpr(addr)) ));
7051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
7054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
7056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_E_to_G_unary_lo64 (
7063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UChar sorb, Int delta,
7064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               HChar* opname, IROp op
7065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
7066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First we need to get the old G value and patch the low 64 bits
7068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of the E operand into it.  Then apply op and write back to G. */
7069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
7070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
7071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
7073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldG0 = newTemp(Ity_V128);
7074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldG1 = newTemp(Ity_V128);
7075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldG0, getXMMReg(gregOfRM(rm)) );
7077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldG1,
7080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop( Iop_SetV128lo64,
7081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(oldG0),
7082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     getXMMRegLane64(eregOfRM(rm), 0)) );
7083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
7086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
7088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
7090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldG1,
7091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop( Iop_SetV128lo64,
7092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(oldG0),
7093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     loadLE(Ity_I64, mkexpr(addr)) ));
7094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
7097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
7099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* SSE integer binary operation:
7104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G = G `op` E   (eLeft == False)
7105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G = E `op` G   (eLeft == True)
7106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
7107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSEint_E_to_G(
7108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UChar sorb, Int delta,
7109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               HChar* opname, IROp op,
7110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Bool   eLeft
7111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
7112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
7114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
7115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
7117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* gpart = getXMMReg(gregOfRM(rm));
7118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* epart = NULL;
7119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      epart = getXMMReg(eregOfRM(rm));
7121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
7123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 1;
7125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr  = disAMode ( &alen, sorb, delta, dis_buf );
7127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      epart = loadLE(Ity_V128, mkexpr(addr));
7128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
7130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
7132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putXMMReg( gregOfRM(rm),
7134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              eLeft ? binop(op, epart, gpart)
7135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	            : binop(op, gpart, epart) );
7136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
7137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for doing SSE FP comparisons. */
7141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void findSSECmpOp ( Bool* needNot, IROp* op,
7143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Int imm8, Bool all_lanes, Int sz )
7144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   imm8 &= 7;
7146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *needNot = False;
7147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *op      = Iop_INVALID;
7148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (imm8 >= 4) {
7149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *needNot = True;
7150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm8 -= 4;
7151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && all_lanes) {
7154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm8) {
7155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: *op = Iop_CmpEQ32Fx4; return;
7156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: *op = Iop_CmpLT32Fx4; return;
7157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: *op = Iop_CmpLE32Fx4; return;
7158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: *op = Iop_CmpUN32Fx4; return;
7159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: break;
7160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && !all_lanes) {
7163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm8) {
7164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: *op = Iop_CmpEQ32F0x4; return;
7165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: *op = Iop_CmpLT32F0x4; return;
7166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: *op = Iop_CmpLE32F0x4; return;
7167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: *op = Iop_CmpUN32F0x4; return;
7168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: break;
7169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 8 && all_lanes) {
7172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm8) {
7173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: *op = Iop_CmpEQ64Fx2; return;
7174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: *op = Iop_CmpLT64Fx2; return;
7175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: *op = Iop_CmpLE64Fx2; return;
7176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: *op = Iop_CmpUN64Fx2; return;
7177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: break;
7178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 8 && !all_lanes) {
7181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm8) {
7182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: *op = Iop_CmpEQ64F0x2; return;
7183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: *op = Iop_CmpLT64F0x2; return;
7184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: *op = Iop_CmpLE64F0x2; return;
7185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: *op = Iop_CmpUN64F0x2; return;
7186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: break;
7187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("findSSECmpOp(x86,guest)");
7190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handles SSE 32F/64F comparisons. */
7193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSEcmp_E_to_G ( UChar sorb, Int delta,
7195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown				HChar* opname, Bool all_lanes, Int sz )
7196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
7198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen, imm8;
7199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    needNot = False;
7201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    op      = Iop_INVALID;
7202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  plain   = newTemp(Ity_V128);
7203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm      = getIByte(delta);
7204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UShort  mask    = 0;
7205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 4 || sz == 8);
7206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm8 = getIByte(delta+1);
7208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
7210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               getXMMReg(eregOfRM(rm))) );
7211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2;
7212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s $%d,%s,%s\n", opname,
7213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            (Int)imm8,
7214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameXMMReg(eregOfRM(rm)),
7215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameXMMReg(gregOfRM(rm)) );
7216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
7218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm8 = getIByte(delta+alen);
7219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( plain,
7221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(
7222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 op,
7223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 getXMMReg(gregOfRM(rm)),
7224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   all_lanes  ? loadLE(Ity_V128, mkexpr(addr))
7225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 : sz == 8    ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
7226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 : /*sz==4*/    unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
7227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             )
7228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
7229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen+1;
7230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s $%d,%s,%s\n", opname,
7231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            (Int)imm8,
7232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            dis_buf,
7233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameXMMReg(gregOfRM(rm)) );
7234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (needNot && all_lanes) {
7237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
7238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop(Iop_NotV128, mkexpr(plain)) );
7239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
7241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (needNot && !all_lanes) {
7242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mask = toUShort( sz==4 ? 0x000F : 0x00FF );
7243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
7244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
7245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else {
7247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm), mkexpr(plain) );
7248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
7251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vector by scalar shift of G by the amount specified at the bottom
7255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of E. */
7256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_shiftG_byE ( UChar sorb, Int delta,
7258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 HChar* opname, IROp op )
7259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
7261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen, size;
7262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    shl, shr, sar;
7264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getIByte(delta);
7265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  g0   = newTemp(Ity_V128);
7266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  g1   = newTemp(Ity_V128);
7267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  amt  = newTemp(Ity_I32);
7268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  amt8 = newTemp(Ity_I8);
7269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
7271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
7273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
7275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
7277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
7278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
7280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
7282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( g0,   getXMMReg(gregOfRM(rm)) );
7284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
7285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shl = shr = sar = False;
7287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   size = 0;
7288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
7289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN16x8: shl = True; size = 32; break;
7290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN32x4: shl = True; size = 32; break;
7291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN64x2: shl = True; size = 64; break;
7292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN16x8: sar = True; size = 16; break;
7293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN32x4: sar = True; size = 32; break;
7294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN16x8: shr = True; size = 16; break;
7295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN32x4: shr = True; size = 32; break;
7296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN64x2: shr = True; size = 64; break;
7297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
7298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shl || shr) {
7301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(
7302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        g1,
7303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr_Mux0X(
7304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
7305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           mkV128(0x0000),
7306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(op, mkexpr(g0), mkexpr(amt8))
7307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
7308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
7309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else
7310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sar) {
7311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(
7312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        g1,
7313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr_Mux0X(
7314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
7315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(op, mkexpr(g0), mkU8(size-1)),
7316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(op, mkexpr(g0), mkexpr(amt8))
7317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
7318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
7319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
7321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0);
7322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putXMMReg( gregOfRM(rm), mkexpr(g1) );
7325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
7326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vector by scalar shift of E by an immediate byte. */
7330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_SSE_shiftE_imm ( Int delta, HChar* opname, IROp op )
7333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    shl, shr, sar;
7335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getIByte(delta);
7336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  e0   = newTemp(Ity_V128);
7337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  e1   = newTemp(Ity_V128);
7338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   amt, size;
7339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(epartIsReg(rm));
7340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(gregOfRM(rm) == 2
7341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
7342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   amt = getIByte(delta+1);
7343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta += 2;
7344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s $%d,%s\n", opname,
7345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      (Int)amt,
7346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameXMMReg(eregOfRM(rm)) );
7347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( e0, getXMMReg(eregOfRM(rm)) );
7348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shl = shr = sar = False;
7350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   size = 0;
7351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
7352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN16x8: shl = True; size = 16; break;
7353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN32x4: shl = True; size = 32; break;
7354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN64x2: shl = True; size = 64; break;
7355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN16x8: sar = True; size = 16; break;
7356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN32x4: sar = True; size = 32; break;
7357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN16x8: shr = True; size = 16; break;
7358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN32x4: shr = True; size = 32; break;
7359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN64x2: shr = True; size = 64; break;
7360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
7361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shl || shr) {
7364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e1, amt >= size
7365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ? mkV128(0x0000)
7366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : binop(op, mkexpr(e0), mkU8(amt))
7367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
7368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else
7369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sar) {
7370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e1, amt >= size
7371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ? binop(op, mkexpr(e0), mkU8(size-1))
7372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : binop(op, mkexpr(e0), mkU8(amt))
7373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
7374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
7376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0);
7377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putXMMReg( eregOfRM(rm), mkexpr(e1) );
7380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
7381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get the current SSE rounding mode. */
7385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
7387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return binop( Iop_And32,
7389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
7390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU32(3) );
7391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_sse_roundingmode ( IRExpr* sseround )
7394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, sseround) == Ity_I32);
7396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
7397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Break a 128-bit value up into four 32-bit ints. */
7400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void breakup128to32s ( IRTemp t128,
7402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			      /*OUTs*/
7403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              IRTemp* t3, IRTemp* t2,
7404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              IRTemp* t1, IRTemp* t0 )
7405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp hi64 = newTemp(Ity_I64);
7407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp lo64 = newTemp(Ity_I64);
7408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
7409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( lo64, unop(Iop_V128to64,   mkexpr(t128)) );
7410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t0 && *t0 == IRTemp_INVALID);
7412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t1 && *t1 == IRTemp_INVALID);
7413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t2 && *t2 == IRTemp_INVALID);
7414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t3 && *t3 == IRTemp_INVALID);
7415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t0 = newTemp(Ity_I32);
7417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t1 = newTemp(Ity_I32);
7418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t2 = newTemp(Ity_I32);
7419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t3 = newTemp(Ity_I32);
7420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t0, unop(Iop_64to32,   mkexpr(lo64)) );
7421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
7422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t2, unop(Iop_64to32,   mkexpr(hi64)) );
7423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
7424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Construct a 128-bit value from four 32-bit ints. */
7427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
7429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              IRTemp t1, IRTemp t0 )
7430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop( Iop_64HLtoV128,
7433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
7434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
7435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
7436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Break a 64-bit value up into four 16-bit ints. */
7439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void breakup64to16s ( IRTemp t64,
7441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             /*OUTs*/
7442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp* t3, IRTemp* t2,
7443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp* t1, IRTemp* t0 )
7444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp hi32 = newTemp(Ity_I32);
7446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp lo32 = newTemp(Ity_I32);
7447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
7448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( lo32, unop(Iop_64to32,   mkexpr(t64)) );
7449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t0 && *t0 == IRTemp_INVALID);
7451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t1 && *t1 == IRTemp_INVALID);
7452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t2 && *t2 == IRTemp_INVALID);
7453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t3 && *t3 == IRTemp_INVALID);
7454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t0 = newTemp(Ity_I16);
7456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t1 = newTemp(Ity_I16);
7457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t2 = newTemp(Ity_I16);
7458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t3 = newTemp(Ity_I16);
7459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t0, unop(Iop_32to16,   mkexpr(lo32)) );
7460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
7461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t2, unop(Iop_32to16,   mkexpr(hi32)) );
7462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
7463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Construct a 64-bit value from four 16-bit ints. */
7466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
7468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp t1, IRTemp t0 )
7469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop( Iop_32HLto64,
7472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
7475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate IR to set the guest %EFLAGS from the pushfl-format image
7478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in the given 32-bit temporary.  The flags that are set are: O S Z A
7479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   C P D ID AC.
7480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   In all cases, code to set AC is generated.  However, VEX actually
7482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ignores the AC value and so can optionally emit an emulation
7483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   warning when it is enabled.  In this routine, an emulation warning
7484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is only emitted if emit_AC_emwarn is True, in which case
7485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   next_insn_EIP must be correct (this allows for correct code
7486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   generation for popfl/popfw).  If emit_AC_emwarn is False,
7487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   next_insn_EIP is unimportant (this allows for easy if kludgey code
7488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   generation for IRET.) */
7489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid set_EFLAGS_from_value ( IRTemp t1,
7492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             Bool   emit_AC_emwarn,
7493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             Addr32 next_insn_EIP )
7494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRTemp(irsb->tyenv,t1) == Ity_I32);
7496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t1 is the flag word.  Mask out everything except OSZACP and set
7498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the flags thunk to X86G_CC_OP_COPY. */
7499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
7500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1,
7502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_And32,
7503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(t1),
7504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
7505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  | X86G_CC_MASK_A | X86G_CC_MASK_Z
7506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  | X86G_CC_MASK_S| X86G_CC_MASK_O )
7507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          )
7508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    )
7509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       );
7510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
7511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
7512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
7513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Also need to set the D flag, which is held in bit 10 of t1.
7515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
7516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
7517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_DFLAG,
7518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr_Mux0X(
7519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_32to8,
7520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And32,
7521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
7522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(1))),
7523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU32(1),
7524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU32(0xFFFFFFFF)))
7525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       );
7526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set the ID flag */
7528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
7529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_IDFLAG,
7530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr_Mux0X(
7531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_32to8,
7532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And32,
7533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
7534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(1))),
7535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU32(0),
7536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU32(1)))
7537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       );
7538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* And set the AC flag.  If setting it 1 to, possibly emit an
7540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      emulation warning. */
7541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
7542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_ACFLAG,
7543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr_Mux0X(
7544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_32to8,
7545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And32,
7546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shr32, mkexpr(t1), mkU8(18)),
7547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(1))),
7548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU32(0),
7549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU32(1)))
7550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       );
7551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (emit_AC_emwarn) {
7553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_emwarn( mkU32(EmWarn_X86_acFlag) );
7554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt(
7555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRStmt_Exit(
7556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( Iop_CmpNE32,
7557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_And32, mkexpr(t1), mkU32(1<<18)),
7558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mkU32(0) ),
7559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Ijk_EmWarn,
7560663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            IRConst_U32( next_insn_EIP ),
7561663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            OFFB_EIP
7562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
7563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
7564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for the SSSE3 (not SSE3) PMULHRSW insns.  Given two 64-bit
7569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   values (aa,bb), computes, for each of the 4 16-bit lanes:
7570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (((aa_lane *s32 bb_lane) >>u 14) + 1) >>u 1
7572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
7573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* dis_PMULHRSW_helper ( IRExpr* aax, IRExpr* bbx )
7574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aa      = newTemp(Ity_I64);
7576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bb      = newTemp(Ity_I64);
7577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aahi32s = newTemp(Ity_I64);
7578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aalo32s = newTemp(Ity_I64);
7579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bbhi32s = newTemp(Ity_I64);
7580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bblo32s = newTemp(Ity_I64);
7581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp rHi     = newTemp(Ity_I64);
7582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp rLo     = newTemp(Ity_I64);
7583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp one32x2 = newTemp(Ity_I64);
7584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(aa, aax);
7585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(bb, bbx);
7586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aahi32s,
7587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_SarN32x2,
7588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_InterleaveHI16x4, mkexpr(aa), mkexpr(aa)),
7589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU8(16) ));
7590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aalo32s,
7591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_SarN32x2,
7592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_InterleaveLO16x4, mkexpr(aa), mkexpr(aa)),
7593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU8(16) ));
7594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( bbhi32s,
7595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_SarN32x2,
7596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_InterleaveHI16x4, mkexpr(bb), mkexpr(bb)),
7597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU8(16) ));
7598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( bblo32s,
7599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_SarN32x2,
7600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_InterleaveLO16x4, mkexpr(bb), mkexpr(bb)),
7601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU8(16) ));
7602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(one32x2, mkU64( (1ULL << 32) + 1 ));
7603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
7604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      rHi,
7605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(
7606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Iop_ShrN32x2,
7607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
7608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_Add32x2,
7609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(
7610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Iop_ShrN32x2,
7611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul32x2, mkexpr(aahi32s), mkexpr(bbhi32s)),
7612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(14)
7613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
7614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkexpr(one32x2)
7615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ),
7616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkU8(1)
7617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
7618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
7619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
7620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      rLo,
7621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(
7622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Iop_ShrN32x2,
7623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
7624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_Add32x2,
7625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(
7626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Iop_ShrN32x2,
7627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul32x2, mkexpr(aalo32s), mkexpr(bblo32s)),
7628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(14)
7629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
7630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkexpr(one32x2)
7631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ),
7632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkU8(1)
7633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
7634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
7635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_CatEvenLanes16x4, mkexpr(rHi), mkexpr(rLo));
7637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for the SSSE3 (not SSE3) PSIGN{B,W,D} insns.  Given two 64-bit
7640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   values (aa,bb), computes, for each lane:
7641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          if aa_lane < 0 then - bb_lane
7643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     else if aa_lane > 0 then bb_lane
7644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     else 0
7645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
7646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* dis_PSIGN_helper ( IRExpr* aax, IRExpr* bbx, Int laneszB )
7647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aa       = newTemp(Ity_I64);
7649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bb       = newTemp(Ity_I64);
7650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp zero     = newTemp(Ity_I64);
7651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bbNeg    = newTemp(Ity_I64);
7652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp negMask  = newTemp(Ity_I64);
7653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp posMask  = newTemp(Ity_I64);
7654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   opSub    = Iop_INVALID;
7655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   opCmpGTS = Iop_INVALID;
7656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (laneszB) {
7658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: opSub = Iop_Sub8x8;  opCmpGTS = Iop_CmpGT8Sx8;  break;
7659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: opSub = Iop_Sub16x4; opCmpGTS = Iop_CmpGT16Sx4; break;
7660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: opSub = Iop_Sub32x2; opCmpGTS = Iop_CmpGT32Sx2; break;
7661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
7662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aa,      aax );
7665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( bb,      bbx );
7666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( zero,    mkU64(0) );
7667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( bbNeg,   binop(opSub,    mkexpr(zero), mkexpr(bb)) );
7668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( negMask, binop(opCmpGTS, mkexpr(zero), mkexpr(aa)) );
7669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( posMask, binop(opCmpGTS, mkexpr(aa),   mkexpr(zero)) );
7670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_Or64,
7673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64, mkexpr(bb),    mkexpr(posMask)),
7674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64, mkexpr(bbNeg), mkexpr(negMask)) );
7675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for the SSSE3 (not SSE3) PABS{B,W,D} insns.  Given a 64-bit
7679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   value aa, computes, for each lane
7680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if aa < 0 then -aa else aa
7682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Note that the result is interpreted as unsigned, so that the
7684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   absolute value of the most negative signed input can be
7685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   represented.
7686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
7687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* dis_PABS_helper ( IRExpr* aax, Int laneszB )
7688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aa      = newTemp(Ity_I64);
7690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp zero    = newTemp(Ity_I64);
7691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aaNeg   = newTemp(Ity_I64);
7692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp negMask = newTemp(Ity_I64);
7693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp posMask = newTemp(Ity_I64);
7694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   opSub   = Iop_INVALID;
7695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   opSarN  = Iop_INVALID;
7696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (laneszB) {
7698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: opSub = Iop_Sub8x8;  opSarN = Iop_SarN8x8;  break;
7699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: opSub = Iop_Sub16x4; opSarN = Iop_SarN16x4; break;
7700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: opSub = Iop_Sub32x2; opSarN = Iop_SarN32x2; break;
7701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
7702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aa,      aax );
7705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( negMask, binop(opSarN, mkexpr(aa), mkU8(8*laneszB-1)) );
7706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( posMask, unop(Iop_Not64, mkexpr(negMask)) );
7707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( zero,    mkU64(0) );
7708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aaNeg,   binop(opSub, mkexpr(zero), mkexpr(aa)) );
7709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_Or64,
7711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64, mkexpr(aa),    mkexpr(posMask)),
7712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64, mkexpr(aaNeg), mkexpr(negMask)) );
7713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* dis_PALIGNR_XMM_helper ( IRTemp hi64,
7716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        IRTemp lo64, Int byteShift )
7717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(byteShift >= 1 && byteShift <= 7);
7719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_Or64,
7721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Shl64, mkexpr(hi64), mkU8(8*(8-byteShift))),
7722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Shr64, mkexpr(lo64), mkU8(8*byteShift))
7723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
7724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate a SIGSEGV followed by a restart of the current instruction
7727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if effective_addr is not 16-aligned.  This is required behaviour
7728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for some SSE3 instructions and all 128-bit SSSE3 instructions.
7729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This assumes that guest_RIP_curr_instr is set correctly! */
7730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void gen_SEGV_if_not_16_aligned ( IRTemp effective_addr )
7731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt(
7733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Exit(
7734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_CmpNE32,
7735663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               binop(Iop_And32,mkexpr(effective_addr),mkU32(0xF)),
7736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU32(0)),
7737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Ijk_SigSEGV,
7738663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         IRConst_U32(guest_EIP_curr_instr),
7739663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         OFFB_EIP
7740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
7741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
7742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for deciding whether a given insn (starting at the opcode
7746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   byte) may validly be used with a LOCK prefix.  The following insns
7747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   may be used with LOCK when their destination operand is in memory.
7748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AFAICS this is exactly the same for both 32-bit and 64-bit mode.
7749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ADD        80 /0,  81 /0,  82 /0,  83 /0,  00,  01
7751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   OR         80 /1,  81 /1,  82 /x,  83 /1,  08,  09
7752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ADC        80 /2,  81 /2,  82 /2,  83 /2,  10,  11
7753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SBB        81 /3,  81 /3,  82 /x,  83 /3,  18,  19
7754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AND        80 /4,  81 /4,  82 /x,  83 /4,  20,  21
7755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SUB        80 /5,  81 /5,  82 /x,  83 /5,  28,  29
7756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XOR        80 /6,  81 /6,  82 /x,  83 /6,  30,  31
7757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DEC        FE /1,  FF /1
7759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   INC        FE /0,  FF /0
7760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NEG        F6 /3,  F7 /3
7762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NOT        F6 /2,  F7 /2
7763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XCHG       86, 87
7765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   BTC        0F BB,  0F BA /7
7767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   BTR        0F B3,  0F BA /6
7768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   BTS        0F AB,  0F BA /5
7769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CMPXCHG    0F B0,  0F B1
7771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CMPXCHG8B  0F C7 /1
7772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XADD       0F C0,  0F C1
7774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------
7776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   80 /0  =  addb $imm8,  rm8
7778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   81 /0  =  addl $imm32, rm32  and  addw $imm16, rm16
7779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   82 /0  =  addb $imm8,  rm8
7780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   83 /0  =  addl $simm8, rm32  and  addw $simm8, rm16
7781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   00     =  addb r8,  rm8
7783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   01     =  addl r32, rm32  and  addw r16, rm16
7784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Same for ADD OR ADC SBB AND SUB XOR
7786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FE /1  = dec rm8
7788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FF /1  = dec rm32  and  dec rm16
7789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FE /0  = inc rm8
7791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FF /0  = inc rm32  and  inc rm16
7792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   F6 /3  = neg rm8
7794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   F7 /3  = neg rm32  and  neg rm16
7795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   F6 /2  = not rm8
7797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   F7 /2  = not rm32  and  not rm16
7798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   0F BB     = btcw r16, rm16    and  btcl r32, rm32
7800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   OF BA /7  = btcw $imm8, rm16  and  btcw $imm8, rm32
7801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Same for BTS, BTR
7803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
7804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool can_be_used_with_LOCK_prefix ( UChar* opc )
7805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (opc[0]) {
7807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x00: case 0x01: case 0x08: case 0x09:
7808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x10: case 0x11: case 0x18: case 0x19:
7809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x20: case 0x21: case 0x28: case 0x29:
7810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x30: case 0x31:
7811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!epartIsReg(opc[1]))
7812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x80: case 0x81: case 0x82: case 0x83:
7816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 6
7817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && !epartIsReg(opc[1]))
7818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFE: case 0xFF:
7822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 1
7823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && !epartIsReg(opc[1]))
7824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF6: case 0xF7:
7828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregOfRM(opc[1]) >= 2 && gregOfRM(opc[1]) <= 3
7829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && !epartIsReg(opc[1]))
7830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x86: case 0x87:
7834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!epartIsReg(opc[1]))
7835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x0F: {
7839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (opc[1]) {
7840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xBB: case 0xB3: case 0xAB:
7841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!epartIsReg(opc[2]))
7842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
7843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xBA:
7845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (gregOfRM(opc[2]) >= 5 && gregOfRM(opc[2]) <= 7
7846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   && !epartIsReg(opc[2]))
7847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
7848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xB0: case 0xB1:
7850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!epartIsReg(opc[2]))
7851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
7852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC7:
7854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (gregOfRM(opc[2]) == 1 && !epartIsReg(opc[2]) )
7855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
7856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0: case 0xC1:
7858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!epartIsReg(opc[2]))
7859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
7860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
7862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } /* switch (opc[1]) */
7864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
7868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* switch (opc[0]) */
7870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
7872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7874663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengstatic IRTemp math_BSWAP ( IRTemp t1, IRType ty )
7875663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng{
7876663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   IRTemp t2 = newTemp(ty);
7877663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (ty == Ity_I32) {
7878663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      assign( t2,
7879663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         binop(
7880663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            Iop_Or32,
7881663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
7882663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            binop(
7883663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               Iop_Or32,
7884663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
7885663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                mkU32(0x00FF0000)),
7886663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               binop(Iop_Or32,
7887663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
7888663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                      mkU32(0x0000FF00)),
7889663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
7890663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                      mkU32(0x000000FF) )
7891663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            )))
7892663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      );
7893663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      return t2;
7894663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
7895663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (ty == Ity_I16) {
7896663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      assign(t2,
7897663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng             binop(Iop_Or16,
7898663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                   binop(Iop_Shl16, mkexpr(t1), mkU8(8)),
7899663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                   binop(Iop_Shr16, mkexpr(t1), mkU8(8)) ));
7900663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      return t2;
7901663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
7902663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(0);
7903663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /*NOTREACHED*/
7904663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   return IRTemp_INVALID;
7905663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng}
7906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
7908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassemble a single instruction                     ---*/
7909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
7910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Disassemble a single instruction into IR.  The instruction is
7912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   located in host memory at &guest_code[delta].  *expect_CAS is set
7913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to True if the resulting IR is expected to contain an IRCAS
7914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   statement, and False if it's not expected to.  This makes it
7915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   possible for the caller of disInstr_X86_WRK to check that
7916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LOCK-prefixed instructions are at least plausibly translated, in
7917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that it becomes possible to check that a (validly) LOCK-prefixed
7918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction generates a translation containing an IRCAS, and
7919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instructions without LOCK prefixes don't generate translations
7920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   containing an IRCAS.
7921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
7922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownDisResult disInstr_X86_WRK (
7924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             /*OUT*/Bool* expect_CAS,
7925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
7926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Bool         resteerCisOk,
7927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             void*        callback_opaque,
7928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Long         delta64,
7929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             VexArchInfo* archinfo,
7930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             VexAbiInfo*  vbi
7931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          )
7932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType    ty;
7934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp    addr, t0, t1, t2, t3, t4, t5, t6;
7935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int       alen;
7936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar     opc, modrm, abyte, pre;
7937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt      d32;
7938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar     dis_buf[50];
7939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int       am_sz, d_sz, n_prefixes;
7940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DisResult dres;
7941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar*    insn; /* used in SSE decoders */
7942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The running delta */
7944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int delta = (Int)delta64;
7945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Holds eip at the start of the insn, so that we can print
7947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      consistent error messages for unimplemented insns. */
7948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int delta_start = delta;
7949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* sz denotes the nominal data-op size of the insn; we change it to
7951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      2 if an 0x66 prefix is seen */
7952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int sz = 4;
7953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* sorb holds the segment-override-prefix byte, if any.  Zero if no
7955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
7956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      indicating the prefix.  */
7957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar sorb = 0;
7958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Gets set to True if a LOCK prefix is seen. */
7960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool pfx_lock = False;
7961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set result defaults. */
7963663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres.whatNext    = Dis_Continue;
7964663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres.len         = 0;
7965663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres.continueAt  = 0;
7966663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres.jk_StopHere = Ijk_INVALID;
7967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *expect_CAS = False;
7969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
7971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guest_EIP_bbstart + delta == guest_EIP_curr_instr);
7973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("\t0x%x:  ", guest_EIP_bbstart+delta);
7974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Spot "Special" instructions (see comment at top of file). */
7976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
7977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar* code = (UChar*)(guest_code + delta);
7978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Spot the 12-byte preamble:
7979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         C1C703   roll $3,  %edi
7980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         C1C70D   roll $13, %edi
7981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         C1C71D   roll $29, %edi
7982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         C1C713   roll $19, %edi
7983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
7984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (code[ 0] == 0xC1 && code[ 1] == 0xC7 && code[ 2] == 0x03 &&
7985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          code[ 3] == 0xC1 && code[ 4] == 0xC7 && code[ 5] == 0x0D &&
7986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          code[ 6] == 0xC1 && code[ 7] == 0xC7 && code[ 8] == 0x1D &&
7987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          code[ 9] == 0xC1 && code[10] == 0xC7 && code[11] == 0x13) {
7988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Got a "Special" instruction preamble.  Which one is it? */
7989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (code[12] == 0x87 && code[13] == 0xDB /* xchgl %ebx,%ebx */) {
7990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* %EDX = client_request ( %EAX ) */
7991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%%edx = client_request ( %%eax )\n");
7992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 14;
7993663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_lit(&dres, Ijk_ClientReq, guest_EIP_bbstart+delta);
7994663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres.whatNext == Dis_StopHere);
7995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
7996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
7997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
7998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (code[12] == 0x87 && code[13] == 0xC9 /* xchgl %ecx,%ecx */) {
7999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* %EAX = guest_NRADDR */
8000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%%eax = guest_NRADDR\n");
8001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 14;
8002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(4, R_EAX, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
8003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
8004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
8006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (code[12] == 0x87 && code[13] == 0xD2 /* xchgl %edx,%edx */) {
8007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* call-noredir *%EAX */
8008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("call-noredir *%%eax\n");
8009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 14;
8010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t1 = newTemp(Ity_I32);
8011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t1, getIReg(4,R_EAX));
8012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I32);
8013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
8014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(4, R_ESP, mkexpr(t2));
8015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta));
8016663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_treg(&dres, Ijk_NoRedir, t1);
8017663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres.whatNext == Dis_StopHere);
8018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
8019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* We don't know what it is. */
8021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
8022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
8023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Handle a couple of weird-ass NOPs that have been observed in the
8027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      wild. */
8028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar* code = (UChar*)(guest_code + delta);
8030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Sun's JVM 1.5.0 uses the following as a NOP:
8031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         26 2E 64 65 90  %es:%cs:%fs:%gs:nop */
8032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (code[0] == 0x26 && code[1] == 0x2E && code[2] == 0x64
8033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && code[3] == 0x65 && code[4] == 0x90) {
8034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%%es:%%cs:%%fs:%%gs:nop\n");
8035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 5;
8036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
8037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Don't barf on recent binutils padding,
8039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         all variants of which are: nopw %cs:0x0(%eax,%eax,1)
8040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66 2e 0f 1f 84 00 00 00 00 00
8041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66 66 2e 0f 1f 84 00 00 00 00 00
8042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66 66 66 2e 0f 1f 84 00 00 00 00 00
8043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
8047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (code[0] == 0x66) {
8048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int data16_cnt;
8049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (data16_cnt = 1; data16_cnt < 6; data16_cnt++)
8050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (code[data16_cnt] != 0x66)
8051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
8052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (code[data16_cnt] == 0x2E && code[data16_cnt + 1] == 0x0F
8053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && code[data16_cnt + 2] == 0x1F && code[data16_cnt + 3] == 0x84
8054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && code[data16_cnt + 4] == 0x00 && code[data16_cnt + 5] == 0x00
8055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && code[data16_cnt + 6] == 0x00 && code[data16_cnt + 7] == 0x00
8056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && code[data16_cnt + 8] == 0x00 ) {
8057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("nopw %%cs:0x0(%%eax,%%eax,1)\n");
8058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 9 + data16_cnt;
8059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
8060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Normal instruction handling starts here. */
8065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Deal with some but not all prefixes:
8067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66(oso)
8068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         F0(lock)
8069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         2E(cs:) 3E(ds:) 26(es:) 64(fs:) 65(gs:) 36(ss:)
8070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Not dealt with (left in place):
8071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         F2 F3
8072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
8073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_prefixes = 0;
8074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (True) {
8075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (n_prefixes > 7) goto decode_failure;
8076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pre = getUChar(delta);
8077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (pre) {
8078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x66:
8079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 2;
8080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
8081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF0:
8082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            pfx_lock = True;
8083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *expect_CAS = True;
8084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
8085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x3E: /* %DS: */
8086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x26: /* %ES: */
8087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x64: /* %FS: */
8088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x65: /* %GS: */
8089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (sorb != 0)
8090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_failure; /* only one seg override allowed */
8091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sorb = pre;
8092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
8093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x2E: { /* %CS: */
8094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* 2E prefix on a conditional branch instruction is a
8095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               branch-prediction hint, which can safely be ignored.  */
8096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UChar op1 = getIByte(delta+1);
8097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UChar op2 = getIByte(delta+2);
8098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((op1 >= 0x70 && op1 <= 0x7F)
8099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                || (op1 == 0xE3)
8100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
8101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0) vex_printf("vex x86->IR: ignoring branch hint\n");
8102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
8103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* All other CS override cases are not handled */
8104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_failure;
8105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
8106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
8107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x36: /* %SS: */
8109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* SS override cases are not handled */
8110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
8111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
8112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto not_a_prefix;
8113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_prefixes++;
8115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
8116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   not_a_prefix:
8119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now we should be looking at the primary opcode byte or the
8121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      leading F2 or F3.  Check that any LOCK prefix is actually
8122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      allowed. */
8123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx_lock) {
8125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (can_be_used_with_LOCK_prefix( (UChar*)&guest_code[delta] )) {
8126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("lock ");
8127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *expect_CAS = False;
8129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
8130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
8135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- The SSE decoder.                             --- */
8136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
8137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* What did I do to deserve SSE ?  Perhaps I was really bad in a
8139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      previous life? */
8140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Note, this doesn't handle SSE2 or SSE3.  That is handled in a
8142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      later section, further on. */
8143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn = (UChar*)&guest_code[delta];
8145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Treat fxsave specially.  It should be doable even on an SSE0
8147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Pentium-II class) CPU.  Hence be prepared to handle it on
8148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      any subarchitecture variant.
8149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
8150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
8152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
8154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRDirty* d;
8155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!epartIsReg(modrm));
8158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
8161b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      gen_SEGV_if_not_16_aligned(addr);
8162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("fxsave %s\n", dis_buf);
8164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Uses dirty helper:
8166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
8167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d = unsafeIRDirty_0_N (
8168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             0/*regparms*/,
8169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             "x86g_dirtyhelper_FXSAVE",
8170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             &x86g_dirtyhelper_FXSAVE,
8171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkIRExprVec_1( mkexpr(addr) )
8172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
8173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->needsBBP = True;
8174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* declare we're writing memory */
8176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->mFx   = Ifx_Write;
8177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->mAddr = mkexpr(addr);
8178663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      d->mSize = 464; /* according to recent Intel docs */
8179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* declare we're reading guest state */
8181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->nFxState = 7;
8182663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vex_bzero(&d->fxState, sizeof(d->fxState));
8183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].fx     = Ifx_Read;
8185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].offset = OFFB_FTOP;
8186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].size   = sizeof(UInt);
8187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].fx     = Ifx_Read;
8189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].offset = OFFB_FPREGS;
8190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].size   = 8 * sizeof(ULong);
8191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].fx     = Ifx_Read;
8193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].offset = OFFB_FPTAGS;
8194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].size   = 8 * sizeof(UChar);
8195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].fx     = Ifx_Read;
8197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].offset = OFFB_FPROUND;
8198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].size   = sizeof(UInt);
8199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].fx     = Ifx_Read;
8201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].offset = OFFB_FC3210;
8202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].size   = sizeof(UInt);
8203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].fx     = Ifx_Read;
8205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].offset = OFFB_XMM0;
8206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].size   = 8 * sizeof(U128);
8207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].fx     = Ifx_Read;
8209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].offset = OFFB_SSEROUND;
8210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].size   = sizeof(UInt);
8211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 images are packed back-to-back.  If not, the value of
8214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 d->fxState[5].size is wrong. */
8215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(16 == sizeof(U128));
8216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Dirty(d) );
8219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /1 = FXRSTOR m512 -- read x87 and SSE state from memory */
8224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 1) {
8226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRDirty* d;
8227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!epartIsReg(modrm));
8230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
8233b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      gen_SEGV_if_not_16_aligned(addr);
8234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("fxrstor %s\n", dis_buf);
8236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Uses dirty helper:
8238b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VexEmWarn x86g_do_FXRSTOR ( VexGuestX86State*, UInt )
8239b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         NOTE:
8240b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            the VexEmWarn value is simply ignored (unlike for FRSTOR)
8241b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      */
8242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d = unsafeIRDirty_0_N (
8243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             0/*regparms*/,
8244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             "x86g_dirtyhelper_FXRSTOR",
8245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             &x86g_dirtyhelper_FXRSTOR,
8246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkIRExprVec_1( mkexpr(addr) )
8247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
8248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->needsBBP = True;
8249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* declare we're reading memory */
8251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->mFx   = Ifx_Read;
8252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->mAddr = mkexpr(addr);
8253663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      d->mSize = 464; /* according to recent Intel docs */
8254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* declare we're writing guest state */
8256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->nFxState = 7;
8257663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vex_bzero(&d->fxState, sizeof(d->fxState));
8258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].fx     = Ifx_Write;
8260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].offset = OFFB_FTOP;
8261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].size   = sizeof(UInt);
8262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].fx     = Ifx_Write;
8264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].offset = OFFB_FPREGS;
8265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].size   = 8 * sizeof(ULong);
8266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].fx     = Ifx_Write;
8268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].offset = OFFB_FPTAGS;
8269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].size   = 8 * sizeof(UChar);
8270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].fx     = Ifx_Write;
8272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].offset = OFFB_FPROUND;
8273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].size   = sizeof(UInt);
8274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].fx     = Ifx_Write;
8276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].offset = OFFB_FC3210;
8277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].size   = sizeof(UInt);
8278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].fx     = Ifx_Write;
8280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].offset = OFFB_XMM0;
8281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].size   = 8 * sizeof(U128);
8282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].fx     = Ifx_Write;
8284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].offset = OFFB_SSEROUND;
8285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].size   = sizeof(UInt);
8286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 images are packed back-to-back.  If not, the value of
8289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 d->fxState[5].size is wrong. */
8290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(16 == sizeof(U128));
8291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Dirty(d) );
8294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------ SSE decoder main ------ */
8299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Skip parts of the decoder which don't apply given the stated
8301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      guest subarchitecture. */
8302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (archinfo->hwcaps == 0/*baseline, no sse at all*/)
8303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto after_sse_decoders;
8304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Otherwise we must be doing sse1 or sse2, so we can at least try
8306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for SSE1 here. */
8307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
8309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
8310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
8311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
8315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
8316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
8318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 55 = ANDNPS -- G = (not G) and E */
8322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
8323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_AndV128 );
8324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 54 = ANDPS -- G = G and E */
8328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
8329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_AndV128 );
8330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
8334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
8335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
8336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
8340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
8341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
8343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2F = COMISS  -- 32F0x4 comparison G,E, and set ZCP */
8347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
8348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
8349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL = newTemp(Ity_F32);
8350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR = newTemp(Ity_F32);
8351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
8354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
8355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)) );
8357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
8360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
8361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("[u]comiss %s,%s\n", dis_buf,
8362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)) );
8363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
8365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
8367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
8368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
8369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_CC_DEP1,
8370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop( Iop_And32,
8371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_CmpF64,
8372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            unop(Iop_F32toF64,mkexpr(argL)),
8373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            unop(Iop_F32toF64,mkexpr(argR))),
8374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(0x45)
8375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          )));
8376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Set NDEP even though it isn't used.  This makes redundant-PUT
8377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         elimination of previous stores to this field work better. */
8378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
8379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
8383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      half xmm */
8384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
8385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg64 = newTemp(Ity_I64);
8386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
8387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
8391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg64, getMMXReg(eregOfRM(modrm)) );
8393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
8394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
8396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
8400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpi2ps %s,%s\n", dis_buf,
8401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
8402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
8405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F(
8407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 0,
8408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_F64toF32,
8409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rmode),
8410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_I32StoF64,
8411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    unop(Iop_64to32, mkexpr(arg64)) )) );
8412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F(
8414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 1,
8415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_F64toF32,
8416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rmode),
8417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_I32StoF64,
8418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    unop(Iop_64HIto32, mkexpr(arg64)) )) );
8419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
8424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      quarter xmm */
8425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
8426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg32 = newTemp(Ity_I32);
8427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
8428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
8431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg32, getIReg(4, eregOfRM(modrm)) );
8433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
8434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
8435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
8436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
8440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsi2ss %s,%s\n", dis_buf,
8441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
8442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
8445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F(
8447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 0,
8448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_F64toF32,
8449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rmode),
8450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_I32StoF64, mkexpr(arg32)) ) );
8451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in mmx, according to prevailing SSE rounding mode */
8457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in mmx, rounding towards zero */
8459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
8460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst64  = newTemp(Ity_I64);
8461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode  = newTemp(Ity_I32);
8462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32lo  = newTemp(Ity_F32);
8463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32hi  = newTemp(Ity_F32);
8464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(insn[1] == 0x2C);
8465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
8467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
8471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
8473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
8475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
8476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
8480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkexpr(addr),
8481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkU32(4) )));
8482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
8483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
8485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
8486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
8489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rmode, mkU32((UInt)Irrm_ZERO) );
8490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
8492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
8495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dst64,
8496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop( Iop_32HLto64,
8497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_F64toI32S,
8498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(rmode),
8499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop( Iop_F32toF64, mkexpr(f32hi) ) ),
8500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_F64toI32S,
8501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(rmode),
8502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop( Iop_F32toF64, mkexpr(f32lo) ) )
8503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
8504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
8505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(gregOfRM(modrm), mkexpr(dst64));
8507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
8511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in ireg, according to prevailing SSE rounding mode */
8512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
8513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in ireg, rounding towards zero */
8514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F
8515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x2D || insn[2] == 0x2C)) {
8516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
8517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32lo = newTemp(Ity_F32);
8518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(insn[2] == 0x2C);
8519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
8522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
8524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
8527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(4, gregOfRM(modrm)));
8528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
8532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
8534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(4, gregOfRM(modrm)));
8535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
8538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, mkU32((UInt)Irrm_ZERO) );
8539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
8541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, gregOfRM(modrm),
8544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_F64toI32S,
8545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(rmode),
8546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop( Iop_F32toF64, mkexpr(f32lo) ) )
8547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
8548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
8553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
8554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
8555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
8560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
8562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
8566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xAE
8567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
8568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp t64 = newTemp(Ity_I64);
8570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp ew = newTemp(Ity_I32);
8571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!epartIsReg(modrm));
8574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
8578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("ldmxcsr %s\n", dis_buf);
8579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* The only thing we observe in %mxcsr is the rounding mode.
8581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Therefore, pass the 32-bit value (SSE native-format control
8582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         word) to a clean helper, getting back a 64-bit value, the
8583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lower half of which is the SSEROUND value to store, and the
8584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         upper half of which is the emulation-warning token which may
8585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         be generated.
8586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
8587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ULong x86h_check_ldmxcsr ( UInt ); */
8588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t64, mkIRExprCCall(
8589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
8590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "x86g_check_ldmxcsr",
8591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &x86g_check_ldmxcsr,
8592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
8593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )
8594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
8595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
8597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
8598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_emwarn( mkexpr(ew) );
8599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Finally, if an emulation warning was reported, side-exit to
8600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the next insn, reporting the warning, so that Valgrind's
8601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dispatcher sees the warning. */
8602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt(
8603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRStmt_Exit(
8604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
8605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Ijk_EmWarn,
8606663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
8607663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            OFFB_EIP
8608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
8609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
8610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F F7 = MASKMOVQ -- 8x8 masked store */
8615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF7) {
8616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool ok = False;
8617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMX( &ok, sorb, sz, delta+1 );
8618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!ok)
8619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
8620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
8624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
8625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
8626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
8630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
8631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
8633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
8637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
8638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
8639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
8643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
8644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
8646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
8650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
8651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
8652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
8655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg( eregOfRM(modrm) ));
8656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
8658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
8659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (insn[1] == 0x28/*movaps*/)
8662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SEGV_if_not_16_aligned( addr );
8663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
8664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_V128, mkexpr(addr)) );
8665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov[ua]ps %s,%s\n", dis_buf,
8666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
8667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
8668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
8673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
8674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F
8675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[1] == 0x29 || insn[1] == 0x11)) {
8676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through; awaiting test case */
8679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (insn[1] == 0x29/*movaps*/)
8682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SEGV_if_not_16_aligned( addr );
8683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
8684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRM(modrm)),
8685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  dis_buf );
8686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
8687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
8688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
8692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
8693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
8694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
8697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
8698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getXMMRegLane64( eregOfRM(modrm), 0 ) );
8699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRM(modrm)));
8701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
8704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
8705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
8706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhps %s,%s\n", dis_buf,
8707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg( gregOfRM(modrm) ));
8708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
8713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
8714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(insn[2])) {
8715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2;
8716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
8717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
8718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
8719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64( gregOfRM(insn[2]),
8720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   1/*upper lane*/ ) );
8721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
8722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               dis_buf);
8723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
8724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
8726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
8729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
8730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
8731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
8734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm),
8735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          0/*lower lane*/,
8736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getXMMRegLane64( eregOfRM(modrm), 1 ));
8737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
8738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
8739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
8742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm),  0/*lower lane*/,
8743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
8744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movlps %s, %s\n",
8745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             dis_buf, nameXMMReg( gregOfRM(modrm) ));
8746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
8751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
8752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(insn[2])) {
8753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2;
8754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
8755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
8756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
8757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64( gregOfRM(insn[2]),
8758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   0/*lower lane*/ ) );
8759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
8760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                dis_buf);
8761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
8762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
8764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
8767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to 4 lowest bits of ireg(G) */
8768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0x50) {
8769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4 && epartIsReg(modrm)) {
8771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int src;
8772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t0 = newTemp(Ity_I32);
8773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I32);
8774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t2 = newTemp(Ity_I32);
8775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t3 = newTemp(Ity_I32);
8776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
8777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         src = eregOfRM(modrm);
8778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t0, binop( Iop_And32,
8779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
8780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(1) ));
8781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t1, binop( Iop_And32,
8782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
8783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(2) ));
8784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2, binop( Iop_And32,
8785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
8786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(4) ));
8787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t3, binop( Iop_And32,
8788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
8789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(8) ));
8790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, gregOfRM(modrm),
8791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Or32,
8792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
8793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
8794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         )
8795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 );
8796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movmskps %s,%s\n", nameXMMReg(src),
8797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameIReg(4, gregOfRM(modrm)));
8798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
8799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
8801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
8804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
8805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0x2B) {
8806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(modrm)) {
8808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
8810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
8811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
8812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 dis_buf,
8813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
8814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
8815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
8816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
8818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F E7 = MOVNTQ -- for us, just a plain MMX store.  Note, the
8822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Intel manual does not say anything about the usual business of
8823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the FP reg tags getting trashed whenever an MMX insn happens.
8824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      So we just leave them alone.
8825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
8826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xE7) {
8827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4 && !epartIsReg(modrm)) {
8829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* do_MMX_preamble(); Intel docs don't specify this */
8830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
8832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movntq %s,%s\n", dis_buf,
8833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameMMXReg(gregOfRM(modrm)));
8834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
8835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
8836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
8838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
8841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (lo 1/4 xmm).  If E is mem, upper 3/4 of G is zeroed out. */
8842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
8843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
8845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane32( gregOfRM(modrm), 0,
8847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getXMMRegLane32( eregOfRM(modrm), 0 ));
8848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRM(modrm)));
8850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
8851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* zero bits 127:64 */
8854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
8855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* zero bits 63:32 */
8856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane32( gregOfRM(modrm), 1, mkU32(0) );
8857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* write bits 31:0 */
8858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane32( gregOfRM(modrm), 0,
8859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I32, mkexpr(addr)) );
8860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movss %s,%s\n", dis_buf,
8861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRM(modrm)));
8862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
8863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
8868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      or lo 1/4 xmm). */
8869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
8870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
8872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through, we don't yet have a test case */
8874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
8877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane32(gregOfRM(modrm), 0) );
8878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)),
8879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              dis_buf);
8880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
8881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
8882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
8886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
8887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
8888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
8892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
8893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
8895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 56 = ORPS -- G = G and E */
8899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
8900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_OrV128 );
8901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
8906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
8907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
8908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
8909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sorb, delta+2, insn[1], "pavgb", False );
8910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
8915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
8916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
8917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
8918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sorb, delta+2, insn[1], "pavgw", False );
8919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
8924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      zero-extend of it in ireg(G). */
8925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xC5) {
8926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
8927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4 && epartIsReg(modrm)) {
8928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp sV = newTemp(Ity_I64);
8929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t5 = newTemp(Ity_I16);
8930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_MMX_preamble();
8931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(sV, getMMXReg(eregOfRM(modrm)));
8932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         breakup64to16s( sV, &t3, &t2, &t1, &t0 );
8933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (insn[3] & 3) {
8934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:  assign(t5, mkexpr(t0)); break;
8935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:  assign(t5, mkexpr(t1)); break;
8936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:  assign(t5, mkexpr(t2)); break;
8937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:  assign(t5, mkexpr(t3)); break;
8938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0); /*NOTREACHED*/
8939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
8941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pextrw $%d,%s,%s\n",
8942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
8943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg(4,gregOfRM(modrm)));
8944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4;
8945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
8946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
8948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
8952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put it into the specified lane of mmx(G). */
8953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
8954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
8955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mmx reg.  t4 is the new lane value.  t5 is the original
8956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mmx value. t6 is the new mmx value. */
8957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int lane;
8958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t4 = newTemp(Ity_I16);
8959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t5 = newTemp(Ity_I64);
8960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t6 = newTemp(Ity_I64);
8961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
8962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
8963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t5, getMMXReg(gregOfRM(modrm)));
8965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup64to16s( t5, &t3, &t2, &t1, &t0 );
8966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t4, getIReg(2, eregOfRM(modrm)));
8969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
8970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lane = insn[3+1-1];
8971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(2,eregOfRM(modrm)),
8973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
8974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
8977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lane = insn[3+alen-1];
8978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t4, loadLE(Ity_I16, mkexpr(addr)));
8979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
8981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
8982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (lane & 3) {
8985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:  assign(t6, mk64from16s(t3,t2,t1,t4)); break;
8986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:  assign(t6, mk64from16s(t3,t2,t4,t0)); break;
8987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:  assign(t6, mk64from16s(t3,t4,t1,t0)); break;
8988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:  assign(t6, mk64from16s(t4,t2,t1,t0)); break;
8989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0); /*NOTREACHED*/
8990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(gregOfRM(modrm), mkexpr(t6));
8992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F EE = PMAXSW -- 16x4 signed max */
8997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
8998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
8999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
9000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sorb, delta+2, insn[1], "pmaxsw", False );
9001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F DE = PMAXUB -- 8x8 unsigned max */
9006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
9007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
9008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
9009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sorb, delta+2, insn[1], "pmaxub", False );
9010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F EA = PMINSW -- 16x4 signed min */
9015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
9016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
9017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
9018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sorb, delta+2, insn[1], "pminsw", False );
9019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F DA = PMINUB -- 8x8 unsigned min */
9024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
9025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
9026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
9027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sorb, delta+2, insn[1], "pminub", False );
9028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
9033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mmx(G), turn them into a byte, and put zero-extend of it in
9034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ireg(G). */
9035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
9036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
9037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_MMX_preamble();
9039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t0 = newTemp(Ity_I64);
9040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I32);
9041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t0, getMMXReg(eregOfRM(modrm)));
9042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t1, mkIRExprCCall(
9043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Ity_I32, 0/*regparms*/,
9044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "x86g_calculate_mmx_pmovmskb",
9045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       &x86g_calculate_mmx_pmovmskb,
9046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprVec_1(mkexpr(t0))));
9047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, gregOfRM(modrm), mkexpr(t1));
9048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameIReg(4,gregOfRM(modrm)));
9050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3;
9051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
9052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
9054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
9058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
9059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
9060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
9061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sorb, delta+2, insn[1], "pmuluh", False );
9062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
9066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 18 /1 = PREFETCH0   -- with various different hints */
9067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 18 /2 = PREFETCH1 */
9068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 18 /3 = PREFETCH2 */
9069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0x18
9070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2])
9071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
9072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* hintstr = "??";
9073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!epartIsReg(modrm));
9076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
9079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
9081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: hintstr = "nta"; break;
9082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: hintstr = "t0"; break;
9083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: hintstr = "t1"; break;
9084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: hintstr = "t2"; break;
9085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0); /*NOTREACHED*/
9086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("prefetch%s %s\n", hintstr, dis_buf);
9089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 0D /0 = PREFETCH  m8 -- 3DNow! prefetch */
9093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 0D /1 = PREFETCHW m8 -- ditto, with some other hint */
9094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0x0D
9095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2])
9096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 1) {
9097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* hintstr = "??";
9098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!epartIsReg(modrm));
9101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
9104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
9106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: hintstr = ""; break;
9107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: hintstr = "w"; break;
9108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0); /*NOTREACHED*/
9109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("prefetch%s %s\n", hintstr, dis_buf);
9112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
9117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF6) {
9118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
9119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
9120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 sorb, delta+2, insn[1], "psadbw", False );
9121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
9126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
9127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int order;
9128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV, s3, s2, s1, s0;
9129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
9130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_I64);
9131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_I64);
9132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
9133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
9134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
9136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         order = (Int)insn[3];
9137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+2;
9138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufw $%d,%s,%s\n", order,
9139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(eregOfRM(modrm)),
9140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
9141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
9144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 order = (Int)insn[2+alen];
9145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufw $%d,%s,%s\n", order,
9147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
9148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
9149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup64to16s( sV, &s3, &s2, &s1, &s0 );
9151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SEL(n) \
9153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dV,
9155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          SEL((order>>2)&3), SEL((order>>0)&3) )
9157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(gregOfRM(modrm), mkexpr(dV));
9159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SEL
9160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
9164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0x53) {
9165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        "rcpps", Iop_Recip32Fx4 );
9168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
9172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
9173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         "rcpss", Iop_Recip32F0x4 );
9176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
9180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0x52) {
9181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        "rsqrtps", Iop_RSqrt32Fx4 );
9184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
9188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
9189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         "rsqrtss", Iop_RSqrt32F0x4 );
9192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /7 = SFENCE -- flush pending operations to memory */
9196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xAE
9197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
9198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 3;
9200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Insert a memory fence.  It's sometimes important that these
9201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         are carried through to the generated code. */
9202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_MBE(Imbe_Fence) );
9203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sfence\n");
9204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
9208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
9209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    select;
9210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV;
9211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_V128);
9213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_V128);
9214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
9216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
9217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
9220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         select = (Int)insn[3];
9221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+2;
9222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("shufps $%d,%s,%s\n", select,
9223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
9224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
9225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         select = (Int)insn[2+alen];
9229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("shufps $%d,%s,%s\n", select,
9231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
9232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
9233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
9239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
9242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
9243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
9244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       SELD((select>>2)&3), SELD((select>>0)&3) )
9245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SELD
9248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SELS
9249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
9254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
9255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        "sqrtps", Iop_Sqrt32Fx4 );
9257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
9262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         "sqrtss", Iop_Sqrt32F0x4 );
9265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
9269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xAE
9270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
9271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!epartIsReg(modrm));
9274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
9277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Fake up a native SSE mxcsr word.  The only thing it depends
9279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         on is SSEROUND[1:0], so call a clean helper to cook it up.
9280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
9281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* UInt x86h_create_mxcsr ( UInt sseround ) */
9282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("stmxcsr %s\n", dis_buf);
9283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr),
9284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkIRExprCCall(
9285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Ity_I32, 0/*regp*/,
9286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "x86g_create_mxcsr", &x86g_create_mxcsr,
9287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkIRExprVec_1( get_sse_roundingmode() )
9288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )
9289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             );
9290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
9294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
9295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
9296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
9300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
9301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
9303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* These just appear to be special cases of SHUFPS */
9309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV;
9311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool hi = toBool(insn[1] == 0x15);
9313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_V128);
9314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_V128);
9315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
9317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
9318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
9321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(eregOfRM(modrm)),
9324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
9325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  dis_buf,
9331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
9332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (hi) {
9338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
9339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
9341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 57 = XORPS -- G = G and E */
9347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
9348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_XorV128 );
9349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
9353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSE decoder.                      --- */
9354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
9355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
9357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the SSE2 decoder.                   --- */
9358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
9359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Skip parts of the decoder which don't apply given the stated
9361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      guest subarchitecture. */
9362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
9363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto after_sse_decoders; /* no SSE2 capabilities */
9364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn = (UChar*)&guest_code[delta];
9366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
9369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
9370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
9375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
9377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
9382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_AndV128 );
9383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 54 = ANDPD -- G = G and E */
9387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
9388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_AndV128 );
9389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
9394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
9395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
9400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
9402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2F = COMISD  -- 64F0x2 comparison G,E, and set ZCP */
9406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
9407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL = newTemp(Ity_F64);
9409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR = newTemp(Ity_F64);
9410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
9413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)) );
9416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("[u]comisd %s,%s\n", dis_buf,
9421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)) );
9422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
9424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
9426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
9427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
9428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_CC_DEP1,
9429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop( Iop_And32,
9430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
9431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(0x45)
9432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          )));
9433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Set NDEP even though it isn't used.  This makes redundant-PUT
9434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         elimination of previous stores to this field work better. */
9435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
9436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      F64 in xmm(G) */
9441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
9442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg64 = newTemp(Ity_I64);
9443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
9446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
9448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
9449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtdq2pd %s,%s\n", dis_buf,
9456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
9460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 0,
9461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)))
9462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
9465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 1,
9466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)))
9467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(G) */
9474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
9475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
9476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRM(modrm)) );
9481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtdq2ps %s,%s\n", dis_buf,
9489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
9493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)  binop( Iop_F64toF32,                    \
9496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(rmode),                   \
9497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_I32StoF64,mkexpr(_t)))
9498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
9500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
9501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
9505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo half xmm(G), and zero upper half */
9511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
9512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
9513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
9517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRM(modrm)) );
9519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
9520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpd2dq %s,%s\n", dis_buf,
9527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
9531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_F64);
9532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_F64);
9533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, unop(Iop_ReinterpI64asF64,
9534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128to64, mkexpr(argV))) );
9535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_ReinterpI64asF64,
9536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128HIto64, mkexpr(argV))) );
9537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)  binop( Iop_F64toI32S,                   \
9539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(rmode),                   \
9540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(_t) )
9541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
9548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in mmx, according to prevailing SSE rounding mode */
9554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in mmx, rounding towards zero */
9556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst64  = newTemp(Ity_I64);
9558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode  = newTemp(Ity_I32);
9559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f64lo  = newTemp(Ity_F64);
9560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f64hi  = newTemp(Ity_F64);
9561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(insn[1] == 0x2C);
9562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
9564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
9570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
9572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
9573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
9577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkexpr(addr),
9578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkU32(8) )));
9579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
9582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
9583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
9586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rmode, mkU32((UInt)Irrm_ZERO) );
9587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
9589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
9592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dst64,
9593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop( Iop_32HLto64,
9594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64hi) ),
9595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo) )
9596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
9597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(gregOfRM(modrm), mkexpr(dst64));
9600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo half xmm(G), and zero upper half */
9605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Note, this is practically identical to CVTPD2DQ.  It would have
9606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      been nicer to merge them together, but the insn[] offsets differ
9607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      by one. */
9608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
9609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
9610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRM(modrm)) );
9615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpd2ps %s,%s\n", dis_buf,
9623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
9627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_F64);
9628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_F64);
9629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, unop(Iop_ReinterpI64asF64,
9630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128to64, mkexpr(argV))) );
9631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_ReinterpI64asF64,
9632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128HIto64, mkexpr(argV))) );
9633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)  binop( Iop_F64toF32,                    \
9635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(rmode),                   \
9636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(_t) )
9637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32(  gregOfRM(modrm), 3, mkU32(0) );
9639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32(  gregOfRM(modrm), 2, mkU32(0) );
9640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
9644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(G) */
9650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
9651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg64 = newTemp(Ity_I64);
9652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Only switch to MMX mode if the source is a MMX register.
9656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            This is inconsistent with all other instructions which
9657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            convert between XMM and (M64 or MMX), which always switch
9658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            to MMX mode even if 64-bit operand is M64 and not MMX.  At
9659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            least, that's what the Intel docs seem to me to say.
9660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Fixes #210264. */
9661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_MMX_preamble();
9662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg64, getMMXReg(eregOfRM(modrm)) );
9663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpi2pd %s,%s\n", dis_buf,
9671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
9675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 0,
9676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)) )
9677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
9680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 1,
9681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)) )
9682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(G) */
9689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
9690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
9691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRM(modrm)) );
9696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtps2dq %s,%s\n", dis_buf,
9704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
9708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is less than ideal.  If it turns out to be a performance
9711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 bottleneck it can be improved. */
9712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)                            \
9713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        binop( Iop_F64toI32S,                   \
9714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rmode),                   \
9715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop( Iop_F32toF64,              \
9716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
9724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      F64 in xmm(G). */
9730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
9731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32lo = newTemp(Ity_F32);
9732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32hi = newTemp(Ity_F32);
9733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
9737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
9738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( f32hi, loadLE(Ity_F32,
9745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
9746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtps2pd %s,%s\n", dis_buf,
9748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F( gregOfRM(modrm), 1,
9752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_F32toF64, mkexpr(f32hi)) );
9753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F( gregOfRM(modrm), 0,
9754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_F32toF64, mkexpr(f32lo)) );
9755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
9760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in ireg, according to prevailing SSE rounding mode */
9761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
9762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in ireg, rounding towards zero */
9763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F
9764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x2D || insn[2] == 0x2C)) {
9765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f64lo = newTemp(Ity_F64);
9767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(insn[2] == 0x2C);
9768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
9771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
9773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
9776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(4, gregOfRM(modrm)));
9777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
9783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(4, gregOfRM(modrm)));
9784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
9787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, mkU32((UInt)Irrm_ZERO) );
9788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
9790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, gregOfRM(modrm),
9793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo)) );
9794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
9799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      low 1/4 xmm(G), according to prevailing SSE rounding mode */
9800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
9801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f64lo = newTemp(Ity_F64);
9803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
9806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
9808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsd2ss %s,%s\n", dis_buf,
9816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
9820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F(
9821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 0,
9822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
9823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
9829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      half xmm */
9830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
9831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg32 = newTemp(Ity_I32);
9832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
9835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg32, getIReg(4, eregOfRM(modrm)) );
9837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
9838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
9839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
9843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsi2sd %s,%s\n", dis_buf,
9845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
9849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 0,
9850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, mkexpr(arg32)) );
9851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
9856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      low half xmm(G) */
9857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
9858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32lo = newTemp(Ity_F32);
9859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
9862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
9864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
9865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
9870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtss2sd %s,%s\n", dis_buf,
9872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F( gregOfRM(modrm), 0,
9876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop( Iop_F32toF64, mkexpr(f32lo) ) );
9877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo half xmm(G), and zero upper half, rounding towards zero */
9883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
9884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
9885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRM(modrm)) );
9890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
9893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvttpd2dq %s,%s\n", dis_buf,
9898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)) );
9899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, mkU32((UInt)Irrm_ZERO) );
9902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_F64);
9904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_F64);
9905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, unop(Iop_ReinterpI64asF64,
9906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128to64, mkexpr(argV))) );
9907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_ReinterpI64asF64,
9908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128HIto64, mkexpr(argV))) );
9909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)  binop( Iop_F64toI32S,                   \
9911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(rmode),                   \
9912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(_t) )
9913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
9920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(G), rounding towards zero */
9926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
9927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
9928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
9932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRM(modrm)) );
9934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
9935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
9937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvttps2dq %s,%s\n", dis_buf,
9942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)) );
9943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, mkU32((UInt)Irrm_ZERO) );
9946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is less than ideal.  If it turns out to be a performance
9949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 bottleneck it can be improved. */
9950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)                            \
9951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        binop( Iop_F64toI32S,                   \
9952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rmode),                   \
9953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop( Iop_F32toF64,              \
9954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
9962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
9967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
9968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
9969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
9973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5E) {
9974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "divsd", Iop_Div64F0x2 );
9976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /5 = LFENCE -- flush pending operations to memory */
9980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /6 = MFENCE -- flush pending operations to memory */
9981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xAE
9982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
9983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
9984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 3;
9986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Insert a memory fence.  It's sometimes important that these
9987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         are carried through to the generated code. */
9988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_MBE(Imbe_Fence) );
9989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
9990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
9994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
9995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
9996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
10000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5F) {
10001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "maxsd", Iop_Max64F0x2 );
10003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
10007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
10008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
10009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
10013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) {
10014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 );
10016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
10020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
10021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
10022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F
10023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
10024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* wot = insn[1]==0x28 ? "apd" :
10025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   insn[1]==0x10 ? "upd" : "dqa";
10026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg( eregOfRM(modrm) ));
10030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)),
10031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
10032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (insn[1] == 0x28/*movapd*/ || insn[1] == 0x6F/*movdqa*/)
10036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SEGV_if_not_16_aligned( addr );
10037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_V128, mkexpr(addr)) );
10039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%s %s,%s\n", wot, dis_buf,
10040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
10041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
10047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
10048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F
10049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[1] == 0x29 || insn[1] == 0x11)) {
10050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* wot = insn[1]==0x29 ? "apd" : "upd";
10051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through; awaiting test case */
10054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (insn[1] == 0x29/*movapd*/)
10057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SEGV_if_not_16_aligned( addr );
10058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRM(modrm)),
10060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf );
10061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
10067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
10068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg(
10072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gregOfRM(modrm),
10073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop( Iop_32UtoV128, getIReg(4, eregOfRM(modrm)) )
10074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
10075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movd %s, %s\n",
10076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
10077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, sorb, delta+2, dis_buf );
10079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg(
10081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gregOfRM(modrm),
10082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
10083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
10084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
10085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
10090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
10091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 4, eregOfRM(modrm),
10095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane32(gregOfRM(modrm), 0) );
10096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movd %s, %s\n",
10097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
10098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, sorb, delta+2, dis_buf );
10100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
10102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane32(gregOfRM(modrm), 0) );
10103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
10109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
10110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( eregOfRM(modrm),
10114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg(gregOfRM(modrm)) );
10115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(eregOfRM(modrm)));
10117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, sorb, delta+2, dis_buf );
10119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
10121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
10128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Unfortunately can't simply use the MOVDQA case since the
10129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      prefix lengths are different (66 vs F3) */
10130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
10131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg( eregOfRM(modrm) ));
10136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRM(modrm)));
10138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_V128, mkexpr(addr)) );
10143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqu %s,%s\n", dis_buf,
10144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRM(modrm)));
10145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
10151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Unfortunately can't simply use the MOVDQA case since the
10152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      prefix lengths are different (66 vs F3) */
10153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
10154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( eregOfRM(modrm),
10159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg(gregOfRM(modrm)) );
10160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(eregOfRM(modrm)));
10162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, sorb, delta+3, dis_buf );
10164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
10172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
10173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_MMX_preamble();
10177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putMMXReg( gregOfRM(modrm),
10178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMRegLane64( eregOfRM(modrm), 0 ));
10179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameMMXReg(gregOfRM(modrm)));
10181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through, apparently no mem case for this insn */
10185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
10189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* These seems identical to MOVHPS.  This instruction encoding is
10190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      completely crazy. */
10191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
10192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through; apparently reg-reg is not possible */
10195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
10199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
10200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhpd %s,%s\n", dis_buf,
10201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg( gregOfRM(modrm) ));
10202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
10207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Again, this seems identical to MOVHPS. */
10208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
10209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(insn[2])) {
10210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2;
10211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
10212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
10213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
10214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64( gregOfRM(insn[2]),
10215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   1/*upper lane*/ ) );
10216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
10217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               dis_buf);
10218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
10224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Identical to MOVLPS ? */
10225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x12) {
10226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through; apparently reg-reg is not possible */
10229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm),  0/*lower lane*/,
10233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
10234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movlpd %s, %s\n",
10235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             dis_buf, nameXMMReg( gregOfRM(modrm) ));
10236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
10241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Identical to MOVLPS ? */
10242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
10243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(insn[2])) {
10244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2;
10245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
10246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
10247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
10248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64( gregOfRM(insn[2]),
10249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   0/*lower lane*/ ) );
10250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
10251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                dis_buf);
10252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      2 lowest bits of ireg(G) */
10259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0x50) {
10260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2 && epartIsReg(modrm)) {
10262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int src;
10263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t0 = newTemp(Ity_I32);
10264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I32);
10265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         src = eregOfRM(modrm);
10267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t0, binop( Iop_And32,
10268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(1) ));
10270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t1, binop( Iop_And32,
10271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(2) ));
10273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, gregOfRM(modrm),
10274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 );
10276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movmskpd %s,%s\n", nameXMMReg(src),
10277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameIReg(4, gregOfRM(modrm)));
10278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F7 = MASKMOVDQU -- store selected bytes of double quadword */
10284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xF7) {
10285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2 && epartIsReg(modrm)) {
10287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp regD    = newTemp(Ity_V128);
10288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp mask    = newTemp(Ity_V128);
10289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp olddata = newTemp(Ity_V128);
10290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp newdata = newTemp(Ity_V128);
10291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                addr    = newTemp(Ity_I32);
10292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
10294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( regD, getXMMReg( gregOfRM(modrm) ));
10295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Unfortunately can't do the obvious thing with SarN8x16
10297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            here since that can't be re-emitted as SSE2 code - no such
10298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            insn. */
10299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(
10300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mask,
10301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_64HLtoV128,
10302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_SarN8x8,
10303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getXMMRegLane64( eregOfRM(modrm), 1 ),
10304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(7) ),
10305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_SarN8x8,
10306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getXMMRegLane64( eregOfRM(modrm), 0 ),
10307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(7) ) ));
10308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( olddata, loadLE( Ity_V128, mkexpr(addr) ));
10309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( newdata,
10310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_OrV128,
10311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_AndV128,
10312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(regD),
10313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(mask) ),
10314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_AndV128,
10315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(olddata),
10316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_NotV128, mkexpr(mask)))) );
10317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), mkexpr(newdata) );
10318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("maskmovdqu %s,%s\n", nameXMMReg( eregOfRM(modrm) ),
10321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg( gregOfRM(modrm) ) );
10322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xE7) {
10329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2 && !epartIsReg(modrm)) {
10331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
10333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movntdq %s,%s\n", dis_buf,
10335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
10336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xC3) {
10344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(modrm)) {
10347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
10349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movnti %s,%s\n", dis_buf,
10350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(4, gregOfRM(modrm)));
10351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
10358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      or lo half xmm).  */
10359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
10360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through, awaiting test case */
10363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* dst: lo half copied, hi half zeroed */
10364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
10367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64( gregOfRM(modrm), 0 ));
10368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
10369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi half). */
10376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
10377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_MMX_preamble();
10381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    unop(Iop_64UtoV128, getMMXReg( eregOfRM(modrm) )) );
10383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
10385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through, apparently no mem case for this insn */
10389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
10393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G (lo half xmm).  Upper half of G is zeroed out. */
10394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
10395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G (lo half xmm).  If E is mem, upper half of G is zeroed out.
10396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If E is reg, upper half of G is unchanged. */
10397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x10)
10398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       || (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7E)) {
10399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm), 0,
10403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getXMMRegLane64( eregOfRM(modrm), 0 ));
10404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (insn[0] == 0xF3/*MOVQ*/) {
10405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* zero bits 127:64 */
10406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
10407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movsd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRM(modrm)));
10410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* zero bits 127:64 */
10414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
10415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* write bits 63:0 */
10416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm), 0,
10417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
10418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movsd %s,%s\n", dis_buf,
10419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRM(modrm)));
10420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      or lo half xmm). */
10427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x11) {
10428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( eregOfRM(modrm), 0,
10432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getXMMRegLane64( gregOfRM(modrm), 0 ));
10433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
10434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(eregOfRM(modrm)));
10435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
10439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64(gregOfRM(modrm), 0) );
10440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
10441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              dis_buf);
10442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
10449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
10450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
10454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
10455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
10457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 56 = ORPD -- G = G and E */
10461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
10462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_OrV128 );
10463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
10468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    select;
10469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_V128);
10470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV = newTemp(Ity_V128);
10471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1 = newTemp(Ity_I64);
10472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s0 = newTemp(Ity_I64);
10473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d1 = newTemp(Ity_I64);
10474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d0 = newTemp(Ity_I64);
10475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
10478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
10481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         select = (Int)insn[3];
10482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+2;
10483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("shufpd $%d,%s,%s\n", select,
10484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
10485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
10486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         select = (Int)insn[2+alen];
10490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("shufpd $%d,%s,%s\n", select,
10492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
10493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
10494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( d0, unop(Iop_V128to64,   mkexpr(dV)) );
10498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s0, unop(Iop_V128to64,   mkexpr(sV)) );
10500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SELD(n) mkexpr((n)==0 ? d0 : d1)
10502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SELS(n) mkexpr((n)==0 ? s0 : s1)
10503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
10505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
10506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
10507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
10508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SELD
10510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SELS
10511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
10517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
10518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        "sqrtpd", Iop_Sqrt64Fx2 );
10519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
10524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3,
10526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         "sqrtsd", Iop_Sqrt64F0x2 );
10527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
10532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
10533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
10538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
10540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* These just appear to be special cases of SHUFPS */
10546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1 = newTemp(Ity_I64);
10548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s0 = newTemp(Ity_I64);
10549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d1 = newTemp(Ity_I64);
10550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d0 = newTemp(Ity_I64);
10551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_V128);
10552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV = newTemp(Ity_V128);
10553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   hi = toBool(insn[1] == 0x15);
10554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
10557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
10560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(eregOfRM(modrm)),
10563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
10564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  dis_buf,
10570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
10571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( d0, unop(Iop_V128to64,   mkexpr(dV)) );
10575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s0, unop(Iop_V128to64,   mkexpr(sV)) );
10577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (hi) {
10579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
10581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
10584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 57 = XORPD -- G = G and E */
10590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
10591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_XorV128 );
10592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6B = PACKSSDW */
10596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
10597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10598b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 "packssdw",
10599b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 Iop_QNarrowBin32Sto16Sx8, True );
10600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 63 = PACKSSWB */
10604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
10605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10606b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 "packsswb",
10607b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 Iop_QNarrowBin16Sto8Sx16, True );
10608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 67 = PACKUSWB */
10612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
10613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10614b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 "packuswb",
10615b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 Iop_QNarrowBin16Sto8Ux16, True );
10616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FC = PADDB */
10620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
10621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddb", Iop_Add8x16, False );
10623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FE = PADDD */
10627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
10628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddd", Iop_Add32x4, False );
10630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F D4 = PADDQ -- add 64x1 */
10635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
10636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
10638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sorb, delta+2, insn[1], "paddq", False );
10639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D4 = PADDQ */
10643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
10644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddq", Iop_Add64x2, False );
10646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FD = PADDW */
10650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
10651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddw", Iop_Add16x8, False );
10653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EC = PADDSB */
10657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
10658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddsb", Iop_QAdd8Sx16, False );
10660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F ED = PADDSW */
10664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
10665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddsw", Iop_QAdd16Sx8, False );
10667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DC = PADDUSB */
10671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
10672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddusb", Iop_QAdd8Ux16, False );
10674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DD = PADDUSW */
10678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
10679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddusw", Iop_QAdd16Ux8, False );
10681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DB = PAND */
10685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
10686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_AndV128 );
10687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DF = PANDN */
10691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
10692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_AndV128 );
10693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E0 = PAVGB */
10697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
10698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pavgb", Iop_Avg8Ux16, False );
10700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E3 = PAVGW */
10704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
10705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pavgw", Iop_Avg16Ux8, False );
10707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 74 = PCMPEQB */
10711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
10712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpeqb", Iop_CmpEQ8x16, False );
10714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 76 = PCMPEQD */
10718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
10719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpeqd", Iop_CmpEQ32x4, False );
10721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 75 = PCMPEQW */
10725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
10726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpeqw", Iop_CmpEQ16x8, False );
10728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 64 = PCMPGTB */
10732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
10733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpgtb", Iop_CmpGT8Sx16, False );
10735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 66 = PCMPGTD */
10739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
10740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpgtd", Iop_CmpGT32Sx4, False );
10742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 65 = PCMPGTW */
10746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
10747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpgtw", Iop_CmpGT16Sx8, False );
10749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      zero-extend of it in ireg(G). */
10754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xC5) {
10755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2 && epartIsReg(modrm)) {
10757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t5 = newTemp(Ity_V128);
10758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t4 = newTemp(Ity_I16);
10759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t5, getXMMReg(eregOfRM(modrm)));
10760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (insn[3] & 7) {
10762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:  assign(t4, unop(Iop_32to16,   mkexpr(t0))); break;
10763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:  assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
10764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:  assign(t4, unop(Iop_32to16,   mkexpr(t1))); break;
10765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:  assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
10766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4:  assign(t4, unop(Iop_32to16,   mkexpr(t2))); break;
10767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5:  assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
10768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6:  assign(t4, unop(Iop_32to16,   mkexpr(t3))); break;
10769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7:  assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
10770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0); /*NOTREACHED*/
10771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
10773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pextrw $%d,%s,%s\n",
10774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
10775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg(4,gregOfRM(modrm)));
10776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4;
10777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
10783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put it into the specified lane of xmm(G). */
10784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
10785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int lane;
10786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t4 = newTemp(Ity_I16);
10787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t4, getIReg(2, eregOfRM(modrm)));
10791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lane = insn[3+1-1];
10793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(2,eregOfRM(modrm)),
10795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
10796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lane = insn[3+alen-1];
10800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t4, loadLE(Ity_I16, mkexpr(addr)));
10801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
10803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
10804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
10807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
10811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      E(xmm or mem) to G(xmm) */
10812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF5) {
10813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1V  = newTemp(Ity_V128);
10814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2V  = newTemp(Ity_V128);
10815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV   = newTemp(Ity_V128);
10816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1Hi = newTemp(Ity_I64);
10817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1Lo = newTemp(Ity_I64);
10818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2Hi = newTemp(Ity_I64);
10819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2Lo = newTemp(Ity_I64);
10820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi  = newTemp(Ity_I64);
10821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo  = newTemp(Ity_I64);
10822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( s1V, getXMMReg(eregOfRM(modrm)) );
10825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
10828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
10831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddwd %s,%s\n", dis_buf,
10833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
10834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2V, getXMMReg(gregOfRM(modrm)) );
10836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
10837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1Lo, unop(Iop_V128to64,   mkexpr(s1V)) );
10838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
10839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2Lo, unop(Iop_V128to64,   mkexpr(s2V)) );
10840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, mkIRExprCCall(
10841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
10842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "x86g_calculate_mmx_pmaddwd",
10843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &x86g_calculate_mmx_pmaddwd,
10844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
10845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
10846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, mkIRExprCCall(
10847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
10848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "x86g_calculate_mmx_pmaddwd",
10849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &x86g_calculate_mmx_pmaddwd,
10850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
10851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
10852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
10853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRM(modrm), mkexpr(dV));
10854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EE = PMAXSW -- 16x8 signed max */
10858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
10859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmaxsw", Iop_Max16Sx8, False );
10861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
10865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
10866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmaxub", Iop_Max8Ux16, False );
10868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EA = PMINSW -- 16x8 signed min */
10872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
10873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pminsw", Iop_Min16Sx8, False );
10875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DA = PMINUB -- 8x16 unsigned min */
10879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
10880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pminub", Iop_Min8Ux16, False );
10882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
10886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(G), turn them into a byte, and put zero-extend of it in
10887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ireg(G).  Doing this directly is just too cumbersome; give up
10888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      therefore and call a helper. */
10889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
10890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
10891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t0 = newTemp(Ity_I64);
10894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I64);
10895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
10896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
10897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t5 = newTemp(Ity_I32);
10898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t5, mkIRExprCCall(
10899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Ity_I32, 0/*regparms*/,
10900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "x86g_calculate_sse_pmovmskb",
10901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       &x86g_calculate_sse_pmovmskb,
10902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
10903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, gregOfRM(modrm), mkexpr(t5));
10904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameIReg(4,gregOfRM(modrm)));
10906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3;
10907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
10913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
10914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmulhuw", Iop_MulHi16Ux8, False );
10916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
10920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
10921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmulhw", Iop_MulHi16Sx8, False );
10923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D5 = PMULHL -- 16x8 multiply */
10927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
10928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmullw", Iop_Mul16x8, False );
10930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      0 to form 64-bit result */
10936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
10937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_I64);
10938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV = newTemp(Ity_I64);
10939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
10940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I32);
10941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
10945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
10948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameMMXReg(gregOfRM(modrm)));
10951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
10954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmuludq %s,%s\n", dis_buf,
10956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameMMXReg(gregOfRM(modrm)));
10957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, unop(Iop_64to32, mkexpr(dV)) );
10960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_64to32, mkexpr(sV)) );
10961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg( gregOfRM(modrm),
10962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
10963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
10968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      half */
10969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is a really poor translation -- could be improved if
10970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      performance critical */
10971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
10972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV;
10973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
10974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_V128);
10975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_V128);
10976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
10977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
10978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I64);
10979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
10981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
10984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
10987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmuludq %s,%s\n", dis_buf,
10992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
10993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
10996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
10999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
11000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
11001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
11002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EB = POR */
11006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
11007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_OrV128 );
11008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
11012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      from E(xmm or mem) to G(xmm) */
11013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF6) {
11014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1V  = newTemp(Ity_V128);
11015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2V  = newTemp(Ity_V128);
11016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV   = newTemp(Ity_V128);
11017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1Hi = newTemp(Ity_I64);
11018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1Lo = newTemp(Ity_I64);
11019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2Hi = newTemp(Ity_I64);
11020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2Lo = newTemp(Ity_I64);
11021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi  = newTemp(Ity_I64);
11022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo  = newTemp(Ity_I64);
11023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
11024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( s1V, getXMMReg(eregOfRM(modrm)) );
11026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psadbw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRM(modrm)));
11029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psadbw %s,%s\n", dis_buf,
11034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRM(modrm)));
11035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2V, getXMMReg(gregOfRM(modrm)) );
11037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1Lo, unop(Iop_V128to64,   mkexpr(s1V)) );
11039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2Lo, unop(Iop_V128to64,   mkexpr(s2V)) );
11041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, mkIRExprCCall(
11042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
11043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "x86g_calculate_mmx_psadbw",
11044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &x86g_calculate_mmx_psadbw,
11045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
11047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, mkIRExprCCall(
11048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
11049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "x86g_calculate_mmx_psadbw",
11050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &x86g_calculate_mmx_psadbw,
11051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
11053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
11059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
11060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int order;
11061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV, s3, s2, s1, s0;
11062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_V128);
11064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_V128);
11065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
11066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
11068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         order = (Int)insn[3];
11069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+2;
11070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufd $%d,%s,%s\n", order,
11071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
11072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
11073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 order = (Int)insn[2+alen];
11077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufd $%d,%s,%s\n", order,
11079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
11080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
11081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SEL(n) \
11085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dV,
11087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
11088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           SEL((order>>2)&3), SEL((order>>0)&3) )
11089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
11090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SEL
11092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
11096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mem) to G(xmm), and copy lower half */
11097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
11098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int order;
11099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
11100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV   = newTemp(Ity_V128);
11102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV   = newTemp(Ity_V128);
11103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sVhi = newTemp(Ity_I64);
11104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dVhi = newTemp(Ity_I64);
11105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
11108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         order = (Int)insn[4];
11109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4+1;
11110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufhw $%d,%s,%s\n", order,
11111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(eregOfRM(modrm)),
11112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
11113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 order = (Int)insn[3+alen];
11117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4+alen;
11118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufhw $%d,%s,%s\n", order,
11119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    dis_buf,
11120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
11121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
11123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
11124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SEL(n) \
11126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dVhi,
11128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          SEL((order>>2)&3), SEL((order>>0)&3) )
11130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
11131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dV, binop( Iop_64HLtoV128,
11132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(dVhi),
11133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_V128to64, mkexpr(sV))) );
11134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SEL
11136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
11140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mem) to G(xmm), and copy upper half */
11141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
11142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int order;
11143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
11144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV   = newTemp(Ity_V128);
11146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV   = newTemp(Ity_V128);
11147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sVlo = newTemp(Ity_I64);
11148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dVlo = newTemp(Ity_I64);
11149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
11152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         order = (Int)insn[4];
11153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4+1;
11154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshuflw $%d,%s,%s\n", order,
11155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(eregOfRM(modrm)),
11156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
11157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 order = (Int)insn[3+alen];
11161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4+alen;
11162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshuflw $%d,%s,%s\n", order,
11163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    dis_buf,
11164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
11165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
11167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
11168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SEL(n) \
11170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dVlo,
11172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          SEL((order>>2)&3), SEL((order>>0)&3) )
11174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
11175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dV, binop( Iop_64HLtoV128,
11176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_V128HIto64, mkexpr(sV)),
11177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(dVlo) ) );
11178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SEL
11180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 72 /6 ib = PSLLD by immediate */
11184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 6) {
11187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
11188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F2 = PSLLD by E */
11192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
11193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
11194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 73 /7 ib = PSLLDQ by immediate */
11198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 7) {
11201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    imm = (Int)insn[3];
11203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    reg = eregOfRM(insn[2]);
11204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
11205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(imm >= 0 && imm <= 255);
11206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 4;
11207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV    = newTemp(Ity_V128);
11209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV    = newTemp(Ity_V128);
11210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi64  = newTemp(Ity_I64);
11211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo64  = newTemp(Ity_I64);
11212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi64r = newTemp(Ity_I64);
11213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo64r = newTemp(Ity_I64);
11214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm >= 16) {
11216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg(reg, mkV128(0x0000));
11217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sV, getXMMReg(reg) );
11221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm == 0) {
11225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkexpr(lo64) );
11226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkexpr(hi64) );
11227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
11229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm == 8) {
11230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkU64(0) );
11231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkexpr(lo64) );
11232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
11234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm > 8) {
11235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkU64(0) );
11236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, binop( Iop_Shl64,
11237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(lo64),
11238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8( 8*(imm-8) ) ));
11239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, binop( Iop_Shl64,
11241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(lo64),
11242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(8 * imm) ));
11243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r,
11244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_Or64,
11245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl64, mkexpr(hi64),
11246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 * imm)),
11247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shr64, mkexpr(lo64),
11248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 * (8 - imm)) )
11249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      )
11250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
11251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(reg, mkexpr(dV));
11254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 73 /6 ib = PSLLQ by immediate */
11258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 6) {
11261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
11262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F3 = PSLLQ by E */
11266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
11267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
11268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 71 /6 ib = PSLLW by immediate */
11272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 6) {
11275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
11276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F1 = PSLLW by E */
11280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
11281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
11282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 72 /4 ib = PSRAD by immediate */
11286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 4) {
11289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
11290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E2 = PSRAD by E */
11294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
11295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
11296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 71 /4 ib = PSRAW by immediate */
11300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 4) {
11303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
11304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E1 = PSRAW by E */
11308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
11309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
11310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 72 /2 ib = PSRLD by immediate */
11314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 2) {
11317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
11318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D2 = PSRLD by E */
11322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
11323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
11324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 73 /3 ib = PSRLDQ by immediate */
11328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 3) {
11331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    imm = (Int)insn[3];
11333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    reg = eregOfRM(insn[2]);
11334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
11335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(imm >= 0 && imm <= 255);
11336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 4;
11337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV    = newTemp(Ity_V128);
11339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV    = newTemp(Ity_V128);
11340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi64  = newTemp(Ity_I64);
11341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo64  = newTemp(Ity_I64);
11342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi64r = newTemp(Ity_I64);
11343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo64r = newTemp(Ity_I64);
11344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm >= 16) {
11346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg(reg, mkV128(0x0000));
11347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sV, getXMMReg(reg) );
11351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm == 0) {
11355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkexpr(lo64) );
11356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkexpr(hi64) );
11357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
11359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm == 8) {
11360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkU64(0) );
11361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkexpr(hi64) );
11362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
11364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm > 8) {
11365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkU64(0) );
11366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, binop( Iop_Shr64,
11367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(hi64),
11368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8( 8*(imm-8) ) ));
11369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, binop( Iop_Shr64,
11371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(hi64),
11372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(8 * imm) ));
11373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r,
11374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_Or64,
11375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shr64, mkexpr(lo64),
11376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 * imm)),
11377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl64, mkexpr(hi64),
11378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 * (8 - imm)) )
11379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      )
11380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
11381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(reg, mkexpr(dV));
11385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 73 /2 ib = PSRLQ by immediate */
11389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 2) {
11392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
11393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D3 = PSRLQ by E */
11397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
11398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
11399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 71 /2 ib = PSRLW by immediate */
11403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 2) {
11406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
11407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D1 = PSRLW by E */
11411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
11412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
11413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F8 = PSUBB */
11417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
11418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubb", Iop_Sub8x16, False );
11420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FA = PSUBD */
11424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
11425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubd", Iop_Sub32x4, False );
11427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F FB = PSUBQ -- sub 64x1 */
11432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
11433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
11434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
11435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sorb, delta+2, insn[1], "psubq", False );
11436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FB = PSUBQ */
11440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
11441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubq", Iop_Sub64x2, False );
11443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F9 = PSUBW */
11447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
11448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubw", Iop_Sub16x8, False );
11450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E8 = PSUBSB */
11454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
11455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubsb", Iop_QSub8Sx16, False );
11457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E9 = PSUBSW */
11461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
11462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubsw", Iop_QSub16Sx8, False );
11464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D8 = PSUBSB */
11468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
11469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubusb", Iop_QSub8Ux16, False );
11471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D9 = PSUBSW */
11475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
11476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubusw", Iop_QSub16Ux8, False );
11478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 68 = PUNPCKHBW */
11482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
11483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckhbw",
11485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveHI8x16, True );
11486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6A = PUNPCKHDQ */
11490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
11491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckhdq",
11493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveHI32x4, True );
11494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6D = PUNPCKHQDQ */
11498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
11499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckhqdq",
11501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveHI64x2, True );
11502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 69 = PUNPCKHWD */
11506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
11507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckhwd",
11509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveHI16x8, True );
11510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 60 = PUNPCKLBW */
11514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
11515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpcklbw",
11517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveLO8x16, True );
11518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 62 = PUNPCKLDQ */
11522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
11523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckldq",
11525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveLO32x4, True );
11526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6C = PUNPCKLQDQ */
11530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
11531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpcklqdq",
11533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveLO64x2, True );
11534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 61 = PUNPCKLWD */
11538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
11539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpcklwd",
11541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveLO16x8, True );
11542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EF = PXOR */
11546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
11547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_XorV128 );
11548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--    /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--    if (insn[0] == 0x0F && insn[1] == 0xAE
11553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--        && (!epartIsReg(insn[2]))
11554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--        && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       Bool store = gregOfRM(insn[2]) == 0;
11556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       vg_assert(sz == 4);
11557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       pair = disAMode ( cb, sorb, eip+2, dis_buf );
11558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       t1   = LOW24(pair);
11559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       eip += 2+HI8(pair);
11560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--                   Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--                   Lit16, (UShort)insn[2],
11563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--                   TempReg, t1 );
11564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       goto decode_success;
11566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--    }
11567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /7 = CLFLUSH -- flush cache line */
11569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
11570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
11571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is something of a hack.  We need to know the size of the
11573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cache line containing addr.  Since we don't (easily), assume
11574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         256 on the basis that no real cache would have a line that
11575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         big.  It's safe to invalidate more stuff than we need, just
11576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         inefficient. */
11577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt lineszB = 256;
11578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
11581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Round addr down to the start of the containing block. */
11583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
11584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_TISTART,
11585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop( Iop_And32,
11586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(addr),
11587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32( ~(lineszB-1) ))) );
11588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(OFFB_TILEN, mkU32(lineszB) ) );
11590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11591663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      jmp_lit(&dres, Ijk_TInval, (Addr32)(guest_EIP_bbstart+delta));
11592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("clflush %s\n", dis_buf);
11594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
11598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSE2 decoder.                     --- */
11599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
11600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
11602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the SSE3 decoder.                   --- */
11603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
11604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Skip parts of the decoder which don't apply given the stated
11606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      guest subarchitecture. */
11607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE3)) */
11608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* In fact this is highly bogus; we accept SSE3 insns even on a
11609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SSE2-only guest since they turn into IR which can be re-emitted
11610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      successfully on an SSE2 host. */
11611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
11612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto after_sse_decoders; /* no SSE3 capabilities */
11613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn = (UChar*)&guest_code[delta];
11615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
11617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      duplicating some lanes (2:2:0:0). */
11618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
11619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      duplicating some lanes (3:3:1:1). */
11620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0xF3 && insn[1] == 0x0F
11621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x12 || insn[2] == 0x16)) {
11622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s3, s2, s1, s0;
11623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV  = newTemp(Ity_V128);
11624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isH = insn[2] == 0x16;
11625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg( eregOfRM(modrm)) );
11630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(eregOfRM(modrm)),
11632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
11633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
11634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
11637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     dis_buf,
11640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameXMMReg(gregOfRM(modrm)));
11641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(modrm),
11646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isH ? mk128from32s( s3, s3, s1, s1 )
11647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : mk128from32s( s2, s2, s0, s0 ) );
11648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
11652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      duplicating some lanes (0:1:0:1). */
11653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x12) {
11654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_V128);
11655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d0 = newTemp(Ity_I64);
11656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg( eregOfRM(modrm)) );
11660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movddup %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
11662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
11663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
11664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
11667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movddup %s,%s\n", dis_buf,
11668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
11669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(modrm), binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
11673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
11677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD0) {
11678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
11679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp eV   = newTemp(Ity_V128);
11680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp gV   = newTemp(Ity_V128);
11681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addV = newTemp(Ity_V128);
11682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp subV = newTemp(Ity_V128);
11683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
11684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, getXMMReg( eregOfRM(modrm)) );
11688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("addsubps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
11690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
11691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("addsubps %s,%s\n", dis_buf,
11695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
11696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( gV, getXMMReg(gregOfRM(modrm)) );
11700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( addV, binop(Iop_Add32Fx4, mkexpr(gV), mkexpr(eV)) );
11702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( subV, binop(Iop_Sub32Fx4, mkexpr(gV), mkexpr(eV)) );
11703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( addV, &a3, &a2, &a1, &a0 );
11705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( subV, &s3, &s2, &s1, &s0 );
11706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(modrm), mk128from32s( a3, s2, a1, s0 ));
11708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
11712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD0) {
11713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp eV   = newTemp(Ity_V128);
11714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp gV   = newTemp(Ity_V128);
11715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addV = newTemp(Ity_V128);
11716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp subV = newTemp(Ity_V128);
11717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp a1     = newTemp(Ity_I64);
11718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s0     = newTemp(Ity_I64);
11719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
11721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, getXMMReg( eregOfRM(modrm)) );
11723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
11725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("addsubpd %s,%s\n", dis_buf,
11730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
11731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( gV, getXMMReg(gregOfRM(modrm)) );
11735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( addV, binop(Iop_Add64Fx2, mkexpr(gV), mkexpr(eV)) );
11737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( subV, binop(Iop_Sub64Fx2, mkexpr(gV), mkexpr(eV)) );
11738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
11740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s0, unop(Iop_V128to64,   mkexpr(subV) ));
11741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(modrm),
11743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
11744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
11748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
11749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F
11750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x7C || insn[2] == 0x7D)) {
11751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
11752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp eV     = newTemp(Ity_V128);
11753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp gV     = newTemp(Ity_V128);
11754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp leftV  = newTemp(Ity_V128);
11755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rightV = newTemp(Ity_V128);
11756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isAdd  = insn[2] == 0x7C;
11757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str    = isAdd ? "add" : "sub";
11758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
11759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, getXMMReg( eregOfRM(modrm)) );
11763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
11765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
11766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("h%sps %s,%s\n", str, dis_buf,
11770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
11771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( gV, getXMMReg(gregOfRM(modrm)) );
11775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( eV, &e3, &e2, &e1, &e0 );
11777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( gV, &g3, &g2, &g1, &g0 );
11778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( leftV,  mk128from32s( e2, e0, g2, g0 ) );
11780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
11781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(modrm),
11783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
11784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(leftV), mkexpr(rightV) ) );
11785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
11789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
11790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
11791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp e1     = newTemp(Ity_I64);
11792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp e0     = newTemp(Ity_I64);
11793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp g1     = newTemp(Ity_I64);
11794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp g0     = newTemp(Ity_I64);
11795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp eV     = newTemp(Ity_V128);
11796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp gV     = newTemp(Ity_V128);
11797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp leftV  = newTemp(Ity_V128);
11798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rightV = newTemp(Ity_V128);
11799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isAdd  = insn[1] == 0x7C;
11800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str    = isAdd ? "add" : "sub";
11801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
11803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, getXMMReg( eregOfRM(modrm)) );
11805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
11807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("h%spd %s,%s\n", str, dis_buf,
11812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRM(modrm)));
11813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( gV, getXMMReg(gregOfRM(modrm)) );
11817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
11819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
11820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
11821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
11822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( leftV,  binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
11824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
11825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(modrm),
11827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
11828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(leftV), mkexpr(rightV) ) );
11829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
11833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xF0) {
11834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
11835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
11837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
11840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_V128, mkexpr(addr)) );
11841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("lddqu %s,%s\n", dis_buf,
11842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRM(modrm)));
11843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
11849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSE3 decoder.                     --- */
11850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
11851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
11853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the SSSE3 decoder.                  --- */
11854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
11855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
11857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Unsigned Bytes (MMX) */
11858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
11859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
11860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV        = newTemp(Ity_I64);
11861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV        = newTemp(Ity_I64);
11862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVoddsSX  = newTemp(Ity_I64);
11863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVevensSX = newTemp(Ity_I64);
11864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dVoddsZX  = newTemp(Ity_I64);
11865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dVevensZX = newTemp(Ity_I64);
11866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
11869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
11870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
11873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
11874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddubsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
11875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameMMXReg(gregOfRM(modrm)));
11876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddubsw %s,%s\n", dis_buf,
11881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameMMXReg(gregOfRM(modrm)));
11882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* compute dV unsigned x sV signed */
11885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVoddsSX,
11886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_SarN16x4, mkexpr(sV), mkU8(8)) );
11887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVevensSX,
11888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_SarN16x4,
11889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_ShlN16x4, mkexpr(sV), mkU8(8)),
11890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(8)) );
11891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dVoddsZX,
11892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_ShrN16x4, mkexpr(dV), mkU8(8)) );
11893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dVevensZX,
11894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_ShrN16x4,
11895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_ShlN16x4, mkexpr(dV), mkU8(8)),
11896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(8)) );
11897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
11899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
11900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_QAdd16Sx4,
11901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul16x4, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
11902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul16x4, mkexpr(sVevensSX), mkexpr(dVevensZX))
11903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
11904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
11905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
11909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Unsigned Bytes (XMM) */
11910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
11911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
11912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV        = newTemp(Ity_V128);
11913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV        = newTemp(Ity_V128);
11914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVoddsSX  = newTemp(Ity_V128);
11915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVevensSX = newTemp(Ity_V128);
11916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dVoddsZX  = newTemp(Ity_V128);
11917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dVevensZX = newTemp(Ity_V128);
11918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
11921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
11924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
11925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddubsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
11927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
11930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddubsw %s,%s\n", dis_buf,
11933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
11934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* compute dV unsigned x sV signed */
11937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVoddsSX,
11938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_SarN16x8, mkexpr(sV), mkU8(8)) );
11939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVevensSX,
11940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_SarN16x8,
11941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_ShlN16x8, mkexpr(sV), mkU8(8)),
11942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(8)) );
11943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dVoddsZX,
11944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_ShrN16x8, mkexpr(dV), mkU8(8)) );
11945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dVevensZX,
11946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_ShrN16x8,
11947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_ShlN16x8, mkexpr(dV), mkU8(8)),
11948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(8)) );
11949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
11951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
11952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_QAdd16Sx8,
11953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul16x8, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
11954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul16x8, mkexpr(sVevensSX), mkexpr(dVevensZX))
11955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
11956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
11957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- these are MMX class insns introduced in SSSE3 ---*** */
11961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 03 = PHADDSW -- 16x4 signed qadd across from E (mem or
11962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mmx) and G to G (mmx). */
11963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 07 = PHSUBSW -- 16x4 signed qsub across from E (mem or
11964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mmx) and G to G (mmx). */
11965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 01 = PHADDW -- 16x4 add across from E (mem or mmx) and G
11966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to G (mmx). */
11967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 05 = PHSUBW -- 16x4 sub across from E (mem or mmx) and G
11968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to G (mmx). */
11969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 02 = PHADDD -- 32x2 add across from E (mem or mmx) and G
11970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to G (mmx). */
11971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 06 = PHSUBD -- 32x2 sub across from E (mem or mmx) and G
11972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to G (mmx). */
11973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
11975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
11976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
11977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
11978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str    = "???";
11979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opV64  = Iop_INVALID;
11980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opCatO = Iop_CatOddLanes16x4;
11981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opCatE = Iop_CatEvenLanes16x4;
11982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV     = newTemp(Ity_I64);
11983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV     = newTemp(Ity_I64);
11984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
11988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
11989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
11990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x01: opV64 = Iop_Add16x4;   str = "addw";  break;
11991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x05: opV64 = Iop_Sub16x4;   str = "subw";  break;
11992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x02: opV64 = Iop_Add32x2;   str = "addd";  break;
11993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x06: opV64 = Iop_Sub32x2;   str = "subd";  break;
11994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
11995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (insn[2] == 0x02 || insn[2] == 0x06) {
11997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         opCatO = Iop_InterleaveHI32x2;
11998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         opCatE = Iop_InterleaveLO32x2;
11999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
12003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
12006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ph%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameMMXReg(gregOfRM(modrm)));
12009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ph%s %s,%s\n", str, dis_buf,
12014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameMMXReg(gregOfRM(modrm)));
12015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
12018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(opV64,
12020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(opCatE,mkexpr(sV),mkexpr(dV)),
12021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(opCatO,mkexpr(sV),mkexpr(dV))
12022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 03 = PHADDSW -- 16x8 signed qadd across from E (mem or
12028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm) and G to G (xmm). */
12029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 07 = PHSUBSW -- 16x8 signed qsub across from E (mem or
12030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm) and G to G (xmm). */
12031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 01 = PHADDW -- 16x8 add across from E (mem or xmm) and
12032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G to G (xmm). */
12033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 05 = PHSUBW -- 16x8 sub across from E (mem or xmm) and
12034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G to G (xmm). */
12035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 02 = PHADDD -- 32x4 add across from E (mem or xmm) and
12036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G to G (xmm). */
12037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 06 = PHSUBD -- 32x4 sub across from E (mem or xmm) and
12038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G to G (xmm). */
12039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
12042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
12043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
12044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str    = "???";
12045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opV64  = Iop_INVALID;
12046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opCatO = Iop_CatOddLanes16x4;
12047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opCatE = Iop_CatEvenLanes16x4;
12048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV     = newTemp(Ity_V128);
12049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV     = newTemp(Ity_V128);
12050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi    = newTemp(Ity_I64);
12051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo    = newTemp(Ity_I64);
12052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi    = newTemp(Ity_I64);
12053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo    = newTemp(Ity_I64);
12054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
12058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
12059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
12060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x01: opV64 = Iop_Add16x4;   str = "addw";  break;
12061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x05: opV64 = Iop_Sub16x4;   str = "subw";  break;
12062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x02: opV64 = Iop_Add32x2;   str = "addd";  break;
12063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x06: opV64 = Iop_Sub32x2;   str = "subd";  break;
12064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
12065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (insn[2] == 0x02 || insn[2] == 0x06) {
12067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         opCatO = Iop_InterleaveHI32x2;
12068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         opCatE = Iop_InterleaveLO32x2;
12069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
12072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg( eregOfRM(modrm)) );
12075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ph%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
12077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ph%s %s,%s\n", str, dis_buf,
12083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             nameXMMReg(gregOfRM(modrm)));
12084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This isn't a particularly efficient way to compute the
12093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         result, but at least it avoids a proliferation of IROps,
12094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         hence avoids complication all the backends. */
12095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
12096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128,
12098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(opV64,
12099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(opCatE,mkexpr(sHi),mkexpr(sLo)),
12100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(opCatO,mkexpr(sHi),mkexpr(sLo))
12101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ),
12102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(opV64,
12103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(opCatE,mkexpr(dHi),mkexpr(dLo)),
12104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(opCatO,mkexpr(dHi),mkexpr(dLo))
12105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )
12106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and Scale
12112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (MMX) */
12113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
12114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_I64);
12116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV = newTemp(Ity_I64);
12117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
12121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
12124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmulhrsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameMMXReg(gregOfRM(modrm)));
12127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmulhrsw %s,%s\n", dis_buf,
12132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameMMXReg(gregOfRM(modrm)));
12133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
12136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_PMULHRSW_helper( mkexpr(sV), mkexpr(dV) )
12138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and
12143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Scale (XMM) */
12144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV  = newTemp(Ity_V128);
12147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV  = newTemp(Ity_V128);
12148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi = newTemp(Ity_I64);
12149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo = newTemp(Ity_I64);
12150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi = newTemp(Ity_I64);
12151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo = newTemp(Ity_I64);
12152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
12155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
12158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmulhrsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
12161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmulhrsw %s,%s\n", dis_buf,
12167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
12168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
12176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128,
12178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PMULHRSW_helper( mkexpr(sHi), mkexpr(dHi) ),
12179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PMULHRSW_helper( mkexpr(sLo), mkexpr(dLo) )
12180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 08 = PSIGNB -- Packed Sign 8x8  (MMX) */
12186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 09 = PSIGNW -- Packed Sign 16x4 (MMX) */
12187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 09 = PSIGND -- Packed Sign 32x2 (MMX) */
12188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
12189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
12190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_I64);
12192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV      = newTemp(Ity_I64);
12193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str     = "???";
12194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    laneszB = 0;
12195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
12197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x08: laneszB = 1; str = "b"; break;
12198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x09: laneszB = 2; str = "w"; break;
12199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x0A: laneszB = 4; str = "d"; break;
12200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
12201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
12206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
12209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psign%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameMMXReg(gregOfRM(modrm)));
12212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psign%s %s,%s\n", str, dis_buf,
12217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameMMXReg(gregOfRM(modrm)));
12218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
12221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_PSIGN_helper( mkexpr(sV), mkexpr(dV), laneszB )
12223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 08 = PSIGNB -- Packed Sign 8x16 (XMM) */
12228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 09 = PSIGNW -- Packed Sign 16x8 (XMM) */
12229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 09 = PSIGND -- Packed Sign 32x4 (XMM) */
12230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
12232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_V128);
12234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV      = newTemp(Ity_V128);
12235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi     = newTemp(Ity_I64);
12236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo     = newTemp(Ity_I64);
12237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi     = newTemp(Ity_I64);
12238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo     = newTemp(Ity_I64);
12239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str     = "???";
12240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    laneszB = 0;
12241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
12243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x08: laneszB = 1; str = "b"; break;
12244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x09: laneszB = 2; str = "w"; break;
12245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x0A: laneszB = 4; str = "d"; break;
12246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
12247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
12251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
12254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psign%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameXMMReg(gregOfRM(modrm)));
12257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psign%s %s,%s\n", str, dis_buf,
12263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameXMMReg(gregOfRM(modrm)));
12264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
12272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128,
12274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PSIGN_helper( mkexpr(sHi), mkexpr(dHi), laneszB ),
12275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PSIGN_helper( mkexpr(sLo), mkexpr(dLo), laneszB )
12276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 1C = PABSB -- Packed Absolute Value 8x8  (MMX) */
12282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 1D = PABSW -- Packed Absolute Value 16x4 (MMX) */
12283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 1E = PABSD -- Packed Absolute Value 32x2 (MMX) */
12284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
12285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
12286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_I64);
12288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str     = "???";
12289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    laneszB = 0;
12290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
12292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1C: laneszB = 1; str = "b"; break;
12293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1D: laneszB = 2; str = "w"; break;
12294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1E: laneszB = 4; str = "d"; break;
12295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
12296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
12303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pabs%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameMMXReg(gregOfRM(modrm)));
12306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pabs%s %s,%s\n", str, dis_buf,
12311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameMMXReg(gregOfRM(modrm)));
12312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
12315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_PABS_helper( mkexpr(sV), laneszB )
12317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 1C = PABSB -- Packed Absolute Value 8x16 (XMM) */
12322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 1D = PABSW -- Packed Absolute Value 16x8 (XMM) */
12323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 1E = PABSD -- Packed Absolute Value 32x4 (XMM) */
12324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
12326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_V128);
12328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi     = newTemp(Ity_I64);
12329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo     = newTemp(Ity_I64);
12330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str     = "???";
12331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    laneszB = 0;
12332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
12334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1C: laneszB = 1; str = "b"; break;
12335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1D: laneszB = 2; str = "w"; break;
12336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1E: laneszB = 4; str = "d"; break;
12337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
12338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
12344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pabs%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
12347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pabs%s %s,%s\n", str, dis_buf,
12353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
12354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
12360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128,
12362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PABS_helper( mkexpr(sHi), laneszB ),
12363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PABS_helper( mkexpr(sLo), laneszB )
12364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 3A 0F = PALIGNR -- Packed Align Right (MMX) */
12370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
12371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV  = newTemp(Ity_I64);
12373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV  = newTemp(Ity_I64);
12374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res = newTemp(Ity_I64);
12375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
12379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
12382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 = (UInt)insn[3+1];
12383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
12384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("palignr $%d,%s,%s\n",  (Int)d32,
12385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameMMXReg(eregOfRM(modrm)),
12386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameMMXReg(gregOfRM(modrm)));
12387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 = (UInt)insn[3+alen];
12391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
12392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("palignr $%d%s,%s\n", (Int)d32,
12393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
12394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
12395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d32 == 0) {
12398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, mkexpr(sV) );
12399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 1 && d32 <= 7) {
12401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res,
12402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Or64,
12403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Shr64, mkexpr(sV), mkU8(8*d32)),
12404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Shl64, mkexpr(dV), mkU8(8*(8-d32))
12405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     )));
12406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 == 8) {
12408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( res, mkexpr(dV) );
12409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 9 && d32 <= 15) {
12411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, binop(Iop_Shr64, mkexpr(dV), mkU8(8*(d32-8))) );
12412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 16 && d32 <= 255) {
12414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, mkU64(0) );
12415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
12417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
12418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg( gregOfRM(modrm), mkexpr(res) );
12420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 0F = PALIGNR -- Packed Align Right (XMM) */
12424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV  = newTemp(Ity_V128);
12427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV  = newTemp(Ity_V128);
12428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi = newTemp(Ity_I64);
12429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo = newTemp(Ity_I64);
12430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi = newTemp(Ity_I64);
12431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo = newTemp(Ity_I64);
12432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rHi = newTemp(Ity_I64);
12433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rLo = newTemp(Ity_I64);
12434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
12437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
12440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 = (UInt)insn[3+1];
12441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
12442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("palignr $%d,%s,%s\n", (Int)d32,
12443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(eregOfRM(modrm)),
12444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
12445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 = (UInt)insn[3+alen];
12450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
12451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("palignr $%d,%s,%s\n", (Int)d32,
12452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    dis_buf,
12453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
12454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d32 == 0) {
12462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkexpr(sHi) );
12463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkexpr(sLo) );
12464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 1 && d32 <= 7) {
12466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, dis_PALIGNR_XMM_helper(dLo, sHi, d32) );
12467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, dis_PALIGNR_XMM_helper(sHi, sLo, d32) );
12468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 == 8) {
12470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkexpr(dLo) );
12471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkexpr(sHi) );
12472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 9 && d32 <= 15) {
12474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, dis_PALIGNR_XMM_helper(dHi, dLo, d32-8) );
12475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, dis_PALIGNR_XMM_helper(dLo, sHi, d32-8) );
12476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 == 16) {
12478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkexpr(dHi) );
12479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkexpr(dLo) );
12480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 17 && d32 <= 23) {
12482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-16))) );
12483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, dis_PALIGNR_XMM_helper(dHi, dLo, d32-16) );
12484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 == 24) {
12486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkU64(0) );
12487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkexpr(dHi) );
12488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 25 && d32 <= 31) {
12490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkU64(0) );
12491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-24))) );
12492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 32 && d32 <= 255) {
12494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkU64(0) );
12495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkU64(0) );
12496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
12498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
12499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
12501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x8 (MMX) */
12508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
12509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_I64);
12511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV      = newTemp(Ity_I64);
12512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
12516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
12519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameMMXReg(gregOfRM(modrm)));
12522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufb %s,%s\n", dis_buf,
12527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameMMXReg(gregOfRM(modrm)));
12528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
12531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
12533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_And64,
12534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* permute the lanes */
12535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(
12536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Iop_Perm8x8,
12537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(dV),
12538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_And64, mkexpr(sV), mkU64(0x0707070707070707ULL))
12539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
12540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* mask off lanes which have (index & 0x80) == 0x80 */
12541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop(Iop_Not64, binop(Iop_SarN8x8, mkexpr(sV), mkU8(7)))
12542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x16 (XMM) */
12548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV         = newTemp(Ity_V128);
12551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV         = newTemp(Ity_V128);
12552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi        = newTemp(Ity_I64);
12553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo        = newTemp(Ity_I64);
12554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi        = newTemp(Ity_I64);
12555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo        = newTemp(Ity_I64);
12556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rHi        = newTemp(Ity_I64);
12557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rLo        = newTemp(Ity_I64);
12558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sevens     = newTemp(Ity_I64);
12559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp mask0x80hi = newTemp(Ity_I64);
12560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp mask0x80lo = newTemp(Ity_I64);
12561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp maskBit3hi = newTemp(Ity_I64);
12562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp maskBit3lo = newTemp(Ity_I64);
12563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sAnd7hi    = newTemp(Ity_I64);
12564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sAnd7lo    = newTemp(Ity_I64);
12565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp permdHi    = newTemp(Ity_I64);
12566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp permdLo    = newTemp(Ity_I64);
12567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
12570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
12573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRM(modrm)));
12576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufb %s,%s\n", dis_buf,
12582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRM(modrm)));
12583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sevens, mkU64(0x0707070707070707ULL) );
12591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*
12593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mask0x80hi = Not(SarN8x8(sHi,7))
12594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      maskBit3hi = SarN8x8(ShlN8x8(sHi,4),7)
12595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sAnd7hi    = And(sHi,sevens)
12596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      permdHi    = Or( And(Perm8x8(dHi,sAnd7hi),maskBit3hi),
12597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       And(Perm8x8(dLo,sAnd7hi),Not(maskBit3hi)) )
12598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      rHi        = And(permdHi,mask0x80hi)
12599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
12600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask0x80hi,
12602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sHi),mkU8(7))));
12603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         maskBit3hi,
12606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_SarN8x8,
12607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_ShlN8x8,mkexpr(sHi),mkU8(4)),
12608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(7)));
12609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(sAnd7hi, binop(Iop_And64,mkexpr(sHi),mkexpr(sevens)));
12611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         permdHi,
12614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
12615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_Or64,
12616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
12617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7hi)),
12618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkexpr(maskBit3hi)),
12619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
12620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7hi)),
12621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_Not64,mkexpr(maskBit3hi))) ));
12622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rHi, binop(Iop_And64,mkexpr(permdHi),mkexpr(mask0x80hi)) );
12624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* And the same for the lower half of the result.  What fun. */
12626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask0x80lo,
12629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sLo),mkU8(7))));
12630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         maskBit3lo,
12633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_SarN8x8,
12634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_ShlN8x8,mkexpr(sLo),mkU8(4)),
12635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(7)));
12636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(sAnd7lo, binop(Iop_And64,mkexpr(sLo),mkexpr(sevens)));
12638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         permdLo,
12641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
12642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_Or64,
12643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
12644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7lo)),
12645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkexpr(maskBit3lo)),
12646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
12647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7lo)),
12648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_Not64,mkexpr(maskBit3lo))) ));
12649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rLo, binop(Iop_And64,mkexpr(permdLo),mkexpr(mask0x80lo)) );
12651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
12653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12658663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
12659663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* 0F 38 F0 = MOVBE m16/32(E), r16/32(G) */
12660663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* 0F 38 F1 = MOVBE r16/32(G), m16/32(E) */
12661663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if ((sz == 2 || sz == 4)
12662663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng       && insn[0] == 0x0F && insn[1] == 0x38
12663663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng       && (insn[2] == 0xF0 || insn[2] == 0xF1)
12664663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng       && !epartIsReg(insn[3])) {
12665663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
12666663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      modrm = insn[3];
12667663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      addr = disAMode(&alen, sorb, delta + 3, dis_buf);
12668663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      delta += 3 + alen;
12669663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      ty = szToITy(sz);
12670663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      IRTemp src = newTemp(ty);
12671663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
12672663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (insn[2] == 0xF0) { /* LOAD */
12673663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         assign(src, loadLE(ty, mkexpr(addr)));
12674663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         IRTemp dst = math_BSWAP(src, ty);
12675663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         putIReg(sz, gregOfRM(modrm), mkexpr(dst));
12676663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         DIP("movbe %s,%s\n", dis_buf, nameIReg(sz, gregOfRM(modrm)));
12677663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      } else { /* STORE */
12678663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         assign(src, getIReg(sz, gregOfRM(modrm)));
12679663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         IRTemp dst = math_BSWAP(src, ty);
12680663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         storeLE(mkexpr(addr), mkexpr(dst));
12681663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         DIP("movbe %s,%s\n", nameIReg(sz, gregOfRM(modrm)), dis_buf);
12682663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      }
12683663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      goto decode_success;
12684663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
12685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSSE3 decoder.                    --- */
12688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the SSE4 decoder                    --- */
12692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 0B /r ib = ROUNDSD imm8, xmm2/m64, xmm1
12695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Partial implementation only -- only deal with cases where
12696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the rounding mode is specified directly by the immediate byte.)
12697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      66 0F 3A 0A /r ib = ROUNDSS imm8, xmm2/m32, xmm1
12698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Limitations ditto)
12699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
12700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x3A
12702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (/*insn[2] == 0x0B || */insn[2] == 0x0A)) {
12703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isD = insn[2] == 0x0B;
12705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src = newTemp(isD ? Ity_F64 : Ity_F32);
12706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res = newTemp(isD ? Ity_F64 : Ity_F32);
12707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    imm = 0;
12708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src,
12713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isD ? getXMMRegLane64F( eregOfRM(modrm), 0 )
12714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : getXMMRegLane32F( eregOfRM(modrm), 0 ) );
12715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = insn[3+1];
12716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (imm & ~3) goto decode_failure;
12717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
12718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "rounds%c $%d,%s,%s\n",
12719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              isD ? 'd' : 's',
12720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm, nameXMMReg( eregOfRM(modrm) ),
12721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   nameXMMReg( gregOfRM(modrm) ) );
12722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, sorb, delta+3, dis_buf );
12724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src, loadLE( isD ? Ity_F64 : Ity_F32, mkexpr(addr) ));
12725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = insn[3+alen];
12726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (imm & ~3) goto decode_failure;
12727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
12728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "roundsd $%d,%s,%s\n",
12729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm, dis_buf, nameXMMReg( gregOfRM(modrm) ) );
12730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* (imm & 3) contains an Intel-encoded rounding mode.  Because
12733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         that encoding is the same as the encoding for IRRoundingMode,
12734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         we can use that value directly in the IR as a rounding
12735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mode. */
12736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(isD ? Iop_RoundF64toInt : Iop_RoundF32toInt,
12737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU32(imm & 3), mkexpr(src)) );
12738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isD)
12740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64F( gregOfRM(modrm), 0, mkexpr(res) );
12741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
12742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane32F( gregOfRM(modrm), 0, mkexpr(res) );
12743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F BD -- LZCNT (count leading zeroes.  An AMD extension,
12748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      which we can only decode if we're sure this is an AMD cpu that
12749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      supports LZCNT, since otherwise it's BSR, which behaves
12750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      differently. */
12751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xBD
12752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && 0 != (archinfo->hwcaps & VEX_HWCAPS_X86_LZCNT)) {
12753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
12754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*IRType*/ ty  = szToITy(sz);
12755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp     src = newTemp(ty);
12756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(src, getIReg(sz, eregOfRM(modrm)));
12759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("lzcnt%c %s, %s\n", nameISize(sz),
12761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameIReg(sz, eregOfRM(modrm)),
12762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameIReg(sz, gregOfRM(modrm)));
12763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, sorb, delta+3, dis_buf );
12765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(src, loadLE(ty, mkexpr(addr)));
12766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("lzcnt%c %s, %s\n", nameISize(sz), dis_buf,
12768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameIReg(sz, gregOfRM(modrm)));
12769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res = gen_LZCNT(ty, src);
12772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(modrm), mkexpr(res));
12773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Update flags.  This is pretty lame .. perhaps can do better
12775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // if this turns out to be performance critical.
12776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // O S A P are cleared.  Z is set if RESULT == 0.
12777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // C is set if SRC is zero.
12778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src32 = newTemp(Ity_I32);
12779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res32 = newTemp(Ity_I32);
12780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src32, widenUto32(mkexpr(src)));
12781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res32, widenUto32(mkexpr(res)));
12782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oszacp = newTemp(Ity_I32);
12784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         oszacp,
12786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_Or32,
12787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Shl32,
12788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto32,
12789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_CmpEQ32, mkexpr(res32), mkU32(0))),
12790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU8(X86G_CC_SHIFT_Z)),
12791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Shl32,
12792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto32,
12793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_CmpEQ32, mkexpr(src32), mkU32(0))),
12794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU8(X86G_CC_SHIFT_C))
12795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
12799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
12800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
12801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(oszacp) ));
12802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSE4 decoder                      --- */
12808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   after_sse_decoders:
12811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- deal with misc 0x67 pfxs (addr size override) -- */
12814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 67 E3 = JCXZ (for JECXZ see below) */
12817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x67 && insn[1] == 0xE3 && sz == 4) {
12818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2;
12819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
12820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta ++;
12821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit(
12822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_CmpEQ16, getIReg(2,R_ECX), mkU16(0)),
12823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Ijk_Boring,
12824663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               IRConst_U32(d32),
12825663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               OFFB_EIP
12826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ));
12827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       DIP("jcxz 0x%x\n", d32);
12828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       goto decode_success;
12829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the baseline insn decoder            -- */
12833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Get the primary opcode. */
12836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   opc = getIByte(delta); delta++;
12837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We get here if the current insn isn't SSE, or this CPU doesn't
12839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      support SSE. */
12840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (opc) {
12842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ Control flow --------------- */
12844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC2: /* RET imm16 */
12846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getUDisp16(delta);
12847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2;
12848663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      dis_ret(&dres, d32);
12849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("ret %d\n", (Int)d32);
12850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
12851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC3: /* RET */
12852663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      dis_ret(&dres, 0);
12853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("ret\n");
12854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
12855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xCF: /* IRET */
12857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Note, this is an extremely kludgey and limited implementation
12858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         of iret.  All it really does is:
12859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            popl %EIP; popl %CS; popl %EFLAGS.
12860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         %CS is set but ignored (as it is in (eg) popw %cs)". */
12861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32); /* ESP */
12862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I32); /* new EIP */
12863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t3 = newTemp(Ity_I32); /* new CS */
12864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t4 = newTemp(Ity_I32); /* new EFLAGS */
12865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIReg(4,R_ESP));
12866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(0) )));
12867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t3, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(4) )));
12868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t4, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(8) )));
12869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Get stuff off stack */
12870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(12)));
12871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* set %CS (which is ignored anyway) */
12872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putSReg( R_CS, unop(Iop_32to16, mkexpr(t3)) );
12873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* set %EFLAGS */
12874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      set_EFLAGS_from_value( t4, False/*!emit_AC_emwarn*/, 0/*unused*/ );
12875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* goto new EIP value */
12876663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      jmp_treg(&dres, Ijk_Ret, t2);
12877663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vassert(dres.whatNext == Dis_StopHere);
12878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("iret (very kludgey)\n");
12879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
12880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE8: /* CALL J4 */
12882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getUDisp32(delta); delta += 4;
12883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 += (guest_EIP_bbstart+delta);
12884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
12885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d32 == guest_EIP_bbstart+delta && getIByte(delta) >= 0x58
12886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         && getIByte(delta) <= 0x5F) {
12887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Specially treat the position-independent-code idiom
12888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 call X
12889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              X: popl %reg
12890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            as
12891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 movl %eip, %reg.
12892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            since this generates better code, but for no other reason. */
12893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int archReg = getIByte(delta) - 0x58;
12894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* vex_printf("-- fPIC thingy\n"); */
12895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, archReg, mkU32(guest_EIP_bbstart+delta));
12896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++; /* Step over the POP */
12897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
12898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* The normal sequence for a call. */
12900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I32);
12901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
12902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_ESP, mkexpr(t1));
12903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
12904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32 )) {
12905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* follow into the call target. */
12906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext   = Dis_ResteerU;
12907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.continueAt = (Addr64)(Addr32)d32;
12908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
12909663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_lit(&dres, Ijk_Call, d32);
12910663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres.whatNext == Dis_StopHere);
12911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
12912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("call 0x%x\n",d32);
12913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
12915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--    case 0xC8: /* ENTER */
12917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       d32 = getUDisp16(eip); eip += 2;
12918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       abyte = getIByte(delta); delta++;
12919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
12920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       vg_assert(sz == 4);
12921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       vg_assert(abyte == 0);
12922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
12923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       t1 = newTemp(cb); t2 = newTemp(cb);
12924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr2(cb, GET,   sz, ArchReg, R_EBP, TempReg, t1);
12925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr2(cb, GET,    4, ArchReg, R_ESP, TempReg, t2);
12926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr2(cb, SUB,    4, Literal, 0,     TempReg, t2);
12927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uLiteral(cb, sz);
12928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_ESP);
12929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr2(cb, STORE,  4, TempReg, t1,    TempReg, t2);
12930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_EBP);
12931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       if (d32) {
12932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, SUB,    4, Literal, 0,     TempReg, t2);
12933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uLiteral(cb, d32);
12934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_ESP);
12935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       }
12936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       DIP("enter 0x%x, 0x%x", d32, abyte);
12937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       break;
12938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC9: /* LEAVE */
12940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
12941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
12942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIReg(4,R_EBP));
12943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* First PUT ESP looks redundant, but need it because ESP must
12944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         always be up-to-date for Memcheck to work... */
12945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, mkexpr(t1));
12946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, loadLE(Ity_I32,mkexpr(t1)));
12947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_EBP, mkexpr(t2));
12948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
12949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("leave\n");
12950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
12951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------- Misc weird-ass insns --------------- */
12953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x27: /* DAA */
12955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2F: /* DAS */
12956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x37: /* AAA */
12957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3F: /* AAS */
12958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* An ugly implementation for some ugly instructions.  Oh
12959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 well. */
12960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4) goto decode_failure;
12961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
12962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I32);
12963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Make up a 32-bit value (t1), with the old value of AX in the
12964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bottom 16 bits, and the old OSZACP bitmask in the upper 16
12965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bits. */
12966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1,
12967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_16HLto32,
12968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   unop(Iop_32to16,
12969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mk_x86g_calculate_eflags_all()),
12970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   getIReg(2, R_EAX)
12971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ));
12972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Call the helper fn, to get a new AX and OSZACP value, and
12973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         poke both back into the guest state.  Also pass the helper
12974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the actual opcode so it knows which of the 4 instructions it
12975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         is doing the computation for. */
12976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(opc == 0x27 || opc == 0x2F || opc == 0x37 || opc == 0x3F);
12977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2,
12978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              mkIRExprCCall(
12979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Ity_I32, 0/*regparm*/, "x86g_calculate_daa_das_aaa_aas",
12980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 &x86g_calculate_daa_das_aaa_aas,
12981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
12982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ));
12983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
12984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
12986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
12987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     stmt( IRStmt_Put( OFFB_CC_DEP1,
12988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And32,
12989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
12990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
12991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    | X86G_CC_MASK_A | X86G_CC_MASK_Z
12992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    | X86G_CC_MASK_S| X86G_CC_MASK_O )
12993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            )
12994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      )
12995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
12996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Set NDEP even though it isn't used.  This makes redundant-PUT
12997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        elimination of previous stores to this field work better. */
12998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
12999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (opc) {
13000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 0x27: DIP("daa\n"); break;
13001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 0x2F: DIP("das\n"); break;
13002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 0x37: DIP("aaa\n"); break;
13003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 0x3F: DIP("aas\n"); break;
13004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        default: vassert(0);
13005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
13006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     break;
13007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13008f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   case 0xD4: /* AAM */
13009f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   case 0xD5: /* AAD */
13010f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d32 = getIByte(delta); delta++;
13011f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (sz != 4 || d32 != 10) goto decode_failure;
13012f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      t1 = newTemp(Ity_I32);
13013f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      t2 = newTemp(Ity_I32);
13014f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* Make up a 32-bit value (t1), with the old value of AX in the
13015f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         bottom 16 bits, and the old OSZACP bitmask in the upper 16
13016f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         bits. */
13017f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(t1,
13018f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root             binop(Iop_16HLto32,
13019f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                   unop(Iop_32to16,
13020f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                        mk_x86g_calculate_eflags_all()),
13021f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                   getIReg(2, R_EAX)
13022f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            ));
13023f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* Call the helper fn, to get a new AX and OSZACP value, and
13024f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         poke both back into the guest state.  Also pass the helper
13025f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         the actual opcode so it knows which of the 2 instructions it
13026f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         is doing the computation for. */
13027f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(t2,
13028f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              mkIRExprCCall(
13029f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 Ity_I32, 0/*regparm*/, "x86g_calculate_aad_aam",
13030f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 &x86g_calculate_aad_aam,
13031f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
13032f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            ));
13033f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
13034f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
13035f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
13036f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13037f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      stmt( IRStmt_Put( OFFB_CC_DEP1,
13038f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                        binop(Iop_And32,
13039f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                              binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
13040f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                              mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
13041f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                                     | X86G_CC_MASK_A | X86G_CC_MASK_Z
13042f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                                     | X86G_CC_MASK_S| X86G_CC_MASK_O )
13043f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                             )
13044f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                       )
13045f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root          );
13046f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* Set NDEP even though it isn't used.  This makes
13047f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         redundant-PUT elimination of previous stores to this field
13048f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         work better. */
13049f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13050f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
13051f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      DIP(opc == 0xD4 ? "aam\n" : "aad\n");
13052f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      break;
13053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ CWD/CDQ -------------------- */
13055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x98: /* CBW */
13057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4) {
13058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
13059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cwde\n");
13060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(sz == 2);
13062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
13063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cbw\n");
13064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x99: /* CWD/CDQ */
13068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
13069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, R_EDX,
13070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(mkSizedOp(ty,Iop_Sar8),
13071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getIReg(sz, R_EAX),
13072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(sz == 2 ? 15 : 31)) );
13073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
13074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ FPU ops -------------------- */
13077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9E: /* SAHF */
13079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      codegen_SAHF();
13080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sahf\n");
13081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9F: /* LAHF */
13084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      codegen_LAHF();
13085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("lahf\n");
13086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9B: /* FWAIT */
13089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ignore? */
13090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("fwait\n");
13091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD8:
13094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD9:
13095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDA:
13096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDB:
13097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDC:
13098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDD:
13099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDE:
13100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDF: {
13101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int  delta0    = delta;
13102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = False;
13103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_FPU ( &decode_OK, sorb, delta );
13104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK) {
13105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = delta0;
13106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
13107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ INC & DEC ------------------ */
13112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x40: /* INC eAX */
13114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x41: /* INC eCX */
13115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x42: /* INC eDX */
13116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x43: /* INC eBX */
13117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x44: /* INC eSP */
13118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x45: /* INC eBP */
13119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x46: /* INC eSI */
13120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x47: /* INC eDI */
13121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
13122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
13123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(ty);
13124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop(mkSizedOp(ty,Iop_Add8),
13125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getIReg(sz, (UInt)(opc - 0x40)),
13126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU(ty,1)) );
13127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_INC_DEC( True, t1, ty );
13128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
13129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
13130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x48: /* DEC eAX */
13133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x49: /* DEC eCX */
13134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x4A: /* DEC eDX */
13135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x4B: /* DEC eBX */
13136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x4C: /* DEC eSP */
13137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x4D: /* DEC eBP */
13138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x4E: /* DEC eSI */
13139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x4F: /* DEC eDI */
13140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
13141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
13142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(ty);
13143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
13144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getIReg(sz, (UInt)(opc - 0x48)),
13145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU(ty,1)) );
13146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_INC_DEC( False, t1, ty );
13147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
13148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
13149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ INT ------------------------ */
13152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xCC: /* INT 3 */
13154663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      jmp_lit(&dres, Ijk_SigTRAP, ((Addr32)guest_EIP_bbstart)+delta);
13155663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vassert(dres.whatNext == Dis_StopHere);
13156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("int $0x3\n");
13157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xCD: /* INT imm8 */
13160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getIByte(delta); delta++;
13161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* For any of the cases where we emit a jump (that is, for all
13163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         currently handled cases), it's important that all ArchRegs
13164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         carry their up-to-date value at this point.  So we declare an
13165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         end-of-block here, which forces any TempRegs caching ArchRegs
13166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to be flushed. */
13167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13168663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      /* Handle int $0x3F .. $0x4F by synthesising a segfault and a
13169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         restart of this instruction (hence the "-2" two lines below,
13170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to get the restart EIP to be this instruction.  This is
13171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         probably Linux-specific and it would be more correct to only
13172663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         do this if the VexAbiInfo says that is what we should do.
13173663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         This used to handle just 0x40-0x43; Jikes RVM uses a larger
13174663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         range (0x3F-0x49), and this allows some slack as well. */
13175663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (d32 >= 0x3F && d32 <= 0x4F) {
13176663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_SigSEGV, ((Addr32)guest_EIP_bbstart)+delta-2);
13177663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("int $0x%x\n", (Int)d32);
13179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
13180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Handle int $0x80 (linux syscalls), int $0x81 and $0x82
13183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (darwin syscalls).  As part of this, note where we are, so we
13184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         can back up the guest to this point if the syscall needs to
13185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         be restarted. */
13186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d32 == 0x80) {
13187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32(guest_EIP_curr_instr) ) );
13189663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Sys_int128, ((Addr32)guest_EIP_bbstart)+delta);
13190663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("int $0x80\n");
13192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
13193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d32 == 0x81) {
13195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32(guest_EIP_curr_instr) ) );
13197663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Sys_int129, ((Addr32)guest_EIP_bbstart)+delta);
13198663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("int $0x81\n");
13200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
13201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d32 == 0x82) {
13203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32(guest_EIP_curr_instr) ) );
13205663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Sys_int130, ((Addr32)guest_EIP_bbstart)+delta);
13206663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("int $0x82\n");
13208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
13209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* none of the above */
13212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_failure;
13213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ Jcond, byte offset --------- */
13215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xEB: /* Jb (jump, byte offset) */
13217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
13219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
13220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext   = Dis_ResteerU;
13221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.continueAt = (Addr64)(Addr32)d32;
13222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13223663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Boring, d32);
13224663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("jmp-8 0x%x\n", d32);
13227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE9: /* Jv (jump, 16/32 offset) */
13230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4); /* JRS added 2004 July 11 */
13231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta);
13232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += sz;
13233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
13234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext   = Dis_ResteerU;
13235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.continueAt = (Addr64)(Addr32)d32;
13236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13237663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Boring, d32);
13238663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("jmp 0x%x\n", d32);
13241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x70:
13244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x71:
13245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x72: /* JBb/JNAEb (jump below) */
13246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x73: /* JNBb/JAEb (jump not below) */
13247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x74: /* JZb/JEb (jump zero) */
13248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x75: /* JNZb/JNEb (jump not zero) */
13249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x76: /* JBEb/JNAb (jump below or equal) */
13250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x77: /* JNBEb/JAb (jump not below or equal) */
13251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x78: /* JSb (jump negative) */
13252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x79: /* JSb (jump not negative) */
13253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7A: /* JP (jump parity even) */
13254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7B: /* JNP/JPO (jump parity odd) */
13255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7C: /* JLb/JNGEb (jump less) */
13256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7D: /* JGEb/JNLb (jump greater or equal) */
13257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7E: /* JLEb/JNGb (jump less or equal) */
13258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7F: /* JGb/JNLEb (jump greater) */
13259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    { Int    jmpDelta;
13260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* comment  = "";
13261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jmpDelta = (Int)getSDisp8(delta);
13262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(-128 <= jmpDelta && jmpDelta < 128);
13263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + jmpDelta;
13264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
13265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (resteerCisOk
13266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && vex_control.guest_chase_cond
13267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && (Addr32)d32 != (Addr32)guest_EIP_bbstart
13268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && jmpDelta < 0
13269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
13270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Speculation: assume this backward branch is taken.  So we
13271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            need to emit a side-exit to the insn following this one,
13272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            on the negation of the condition, and continue at the
13273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            branch target address (d32).  If we wind up back at the
13274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            first instruction of the trace, just stop; it's better to
13275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            let the IR loop unroller handle that case. */
13276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Exit(
13277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
13278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Ijk_Boring,
13279663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                  IRConst_U32(guest_EIP_bbstart+delta),
13280663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                  OFFB_EIP ) );
13281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext   = Dis_ResteerC;
13282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.continueAt = (Addr64)(Addr32)d32;
13283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         comment = "(assumed taken)";
13284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
13286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (resteerCisOk
13287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && vex_control.guest_chase_cond
13288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && (Addr32)d32 != (Addr32)guest_EIP_bbstart
13289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && jmpDelta >= 0
13290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && resteerOkFn( callback_opaque,
13291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          (Addr64)(Addr32)(guest_EIP_bbstart+delta)) ) {
13292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Speculation: assume this forward branch is not taken.  So
13293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            we need to emit a side-exit to d32 (the dest) and continue
13294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            disassembling at the insn immediately following this
13295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            one. */
13296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Exit(
13297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mk_x86g_calculate_condition((X86Condcode)(opc - 0x70)),
13298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Ijk_Boring,
13299663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                  IRConst_U32(d32),
13300663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                  OFFB_EIP ) );
13301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext   = Dis_ResteerC;
13302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.continueAt = (Addr64)(Addr32)(guest_EIP_bbstart+delta);
13303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         comment = "(assumed not taken)";
13304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else {
13306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Conservative default translation - end the block at this
13307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            point. */
13308663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jcc_01( &dres, (X86Condcode)(opc - 0x70),
13309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 (Addr32)(guest_EIP_bbstart+delta), d32);
13310663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("j%s-8 0x%x %s\n", name_X86Condcode(opc - 0x70), d32, comment);
13313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
13315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE3: /* JECXZ (for JCXZ see above) */
13317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4) goto decode_failure;
13318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta ++;
13320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit(
13321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_CmpEQ32, getIReg(4,R_ECX), mkU32(0)),
13322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Ijk_Boring,
13323663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            IRConst_U32(d32),
13324663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            OFFB_EIP
13325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ));
13326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("jecxz 0x%x\n", d32);
13327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
13330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE1: /* LOOPE  disp8: decrement count, jump if count != 0 && ZF==1 */
13331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE2: /* LOOP   disp8: decrement count, jump if count != 0 */
13332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    { /* Again, the docs say this uses ECX/CX as a count depending on
13333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the address size override, not the operand one.  Since we
13334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         don't handle address size overrides, I guess that means
13335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ECX. */
13336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* zbit  = NULL;
13337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* count = NULL;
13338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* cond  = NULL;
13339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar*  xtra  = NULL;
13340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4) goto decode_failure;
13342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
13344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ECX, binop(Iop_Sub32, getIReg(4,R_ECX), mkU32(1)));
13345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      count = getIReg(4,R_ECX);
13347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cond = binop(Iop_CmpNE32, count, mkU32(0));
13348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (opc) {
13349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xE2:
13350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xtra = "";
13351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
13352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xE1:
13353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xtra = "e";
13354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            zbit = mk_x86g_calculate_condition( X86CondZ );
13355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    cond = mkAnd1(cond, zbit);
13356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
13357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xE0:
13358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xtra = "ne";
13359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            zbit = mk_x86g_calculate_condition( X86CondNZ );
13360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    cond = mkAnd1(cond, zbit);
13361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
13362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
13363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    vassert(0);
13364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13365663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U32(d32), OFFB_EIP) );
13366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("loop%s 0x%x\n", xtra, d32);
13368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
13370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ IMUL ----------------------- */
13372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x69: /* IMUL Iv, Ev, Gv */
13374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
13375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x6B: /* IMUL Ib, Ev, Gv */
13377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
13378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ MOV ------------------------ */
13381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x88: /* MOV Gb,Eb */
13383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_G_E(sorb, 1, delta);
13384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x89: /* MOV Gv,Ev */
13387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_G_E(sorb, sz, delta);
13388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8A: /* MOV Eb,Gb */
13391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_E_G(sorb, 1, delta);
13392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8B: /* MOV Ev,Gv */
13395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_E_G(sorb, sz, delta);
13396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8D: /* LEA M,Gv */
13399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4)
13400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
13401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
13402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm))
13403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
13404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* NOTE!  this is the one place where a segment override prefix
13405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         has no effect on the address calculation.  Therefore we pass
13406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         zero instead of sorb here. */
13407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
13408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
13409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(modrm), mkexpr(addr));
13410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
13411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameIReg(sz,gregOfRM(modrm)));
13412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
13415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_Sw_Ew(sorb, sz, delta);
13416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
13419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_Ew_Sw(sorb, delta);
13420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA0: /* MOV Ob,AL */
13423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
13424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Fall through ... */
13425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA1: /* MOV Ov,eAX */
13426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getUDisp32(delta); delta += 4;
13427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
13428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = newTemp(Ity_I32);
13429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
13431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
13432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                d32, nameIReg(sz,R_EAX));
13433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA2: /* MOV Ob,AL */
13436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
13437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Fall through ... */
13438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA3: /* MOV eAX,Ov */
13439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getUDisp32(delta); delta += 4;
13440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
13441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = newTemp(Ity_I32);
13442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
13444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
13445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                sorbTxt(sorb), d32);
13446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB0: /* MOV imm,AL */
13449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB1: /* MOV imm,CL */
13450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB2: /* MOV imm,DL */
13451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB3: /* MOV imm,BL */
13452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB4: /* MOV imm,AH */
13453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB5: /* MOV imm,CH */
13454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB6: /* MOV imm,DH */
13455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB7: /* MOV imm,BH */
13456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getIByte(delta); delta += 1;
13457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(1, opc-0xB0, mkU8(d32));
13458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
13459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB8: /* MOV imm,eAX */
13462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB9: /* MOV imm,eCX */
13463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBA: /* MOV imm,eDX */
13464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBB: /* MOV imm,eBX */
13465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBC: /* MOV imm,eSP */
13466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBD: /* MOV imm,eBP */
13467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBE: /* MOV imm,eSI */
13468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBF: /* MOV imm,eDI */
13469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getUDisp(sz,delta); delta += sz;
13470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
13471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
13472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC6: /* MOV Ib,Eb */
13475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
13476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_Mov_I_E;
13477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC7: /* MOV Iv,Ev */
13478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_Mov_I_E;
13479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_Mov_I_E:
13481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
13482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++; /* mod/rm byte */
13484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 = getUDisp(sz,delta); delta += sz;
13485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
13486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
13487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameIReg(sz,eregOfRM(modrm)));
13488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
13490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
13491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 = getUDisp(sz,delta); delta += sz;
13492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
13493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
13494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ opl imm, A ----------------- */
13498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x04: /* ADD Ib, AL */
13500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_Add8, True, delta, "add" );
13501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x05: /* ADD Iv, eAX */
13503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Add8, True, delta, "add" );
13504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0C: /* OR Ib, AL */
13507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_Or8, True, delta, "or" );
13508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0D: /* OR Iv, eAX */
13510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
13511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x14: /* ADC Ib, AL */
13514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, True, Iop_Add8, True, delta, "adc" );
13515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x15: /* ADC Iv, eAX */
13517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, True, Iop_Add8, True, delta, "adc" );
13518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1C: /* SBB Ib, AL */
13521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
13522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1D: /* SBB Iv, eAX */
13524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, True, Iop_Sub8, True, delta, "sbb" );
13525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x24: /* AND Ib, AL */
13528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_And8, True, delta, "and" );
13529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x25: /* AND Iv, eAX */
13531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
13532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2C: /* SUB Ib, AL */
13535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_Sub8, True, delta, "sub" );
13536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2D: /* SUB Iv, eAX */
13538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
13539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x34: /* XOR Ib, AL */
13542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_Xor8, True, delta, "xor" );
13543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x35: /* XOR Iv, eAX */
13545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
13546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3C: /* CMP Ib, AL */
13549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_Sub8, False, delta, "cmp" );
13550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3D: /* CMP Iv, eAX */
13552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
13553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA8: /* TEST Ib, AL */
13556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_And8, False, delta, "test" );
13557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA9: /* TEST Iv, eAX */
13559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
13560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ opl Ev, Gv ----------------- */
13563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x02: /* ADD Eb,Gb */
13565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
13566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x03: /* ADD Ev,Gv */
13568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
13569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0A: /* OR Eb,Gb */
13572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
13573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0B: /* OR Ev,Gv */
13575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
13576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x12: /* ADC Eb,Gb */
13579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
13580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x13: /* ADC Ev,Gv */
13582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
13583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1A: /* SBB Eb,Gb */
13586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
13587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1B: /* SBB Ev,Gv */
13589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
13590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x22: /* AND Eb,Gb */
13593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
13594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x23: /* AND Ev,Gv */
13596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
13597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2A: /* SUB Eb,Gb */
13600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
13601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2B: /* SUB Ev,Gv */
13603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
13604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x32: /* XOR Eb,Gb */
13607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
13608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x33: /* XOR Ev,Gv */
13610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
13611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3A: /* CMP Eb,Gb */
13614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
13615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3B: /* CMP Ev,Gv */
13617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
13618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x84: /* TEST Eb,Gb */
13621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
13622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x85: /* TEST Ev,Gv */
13624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
13625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ opl Gv, Ev ----------------- */
13628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x00: /* ADD Gb,Eb */
13630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Add8, True, 1, delta, "add" );
13632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x01: /* ADD Gv,Ev */
13634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Add8, True, sz, delta, "add" );
13636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x08: /* OR Gb,Eb */
13639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Or8, True, 1, delta, "or" );
13641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x09: /* OR Gv,Ev */
13643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Or8, True, sz, delta, "or" );
13645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x10: /* ADC Gb,Eb */
13648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Add8, True, 1, delta, "adc" );
13650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x11: /* ADC Gv,Ev */
13652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Add8, True, sz, delta, "adc" );
13654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x18: /* SBB Gb,Eb */
13657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Sub8, True, 1, delta, "sbb" );
13659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x19: /* SBB Gv,Ev */
13661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Sub8, True, sz, delta, "sbb" );
13663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x20: /* AND Gb,Eb */
13666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_And8, True, 1, delta, "and" );
13668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x21: /* AND Gv,Ev */
13670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_And8, True, sz, delta, "and" );
13672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x28: /* SUB Gb,Eb */
13675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Sub8, True, 1, delta, "sub" );
13677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x29: /* SUB Gv,Ev */
13679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Sub8, True, sz, delta, "sub" );
13681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x30: /* XOR Gb,Eb */
13684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Xor8, True, 1, delta, "xor" );
13686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x31: /* XOR Gv,Ev */
13688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Xor8, True, sz, delta, "xor" );
13690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x38: /* CMP Gb,Eb */
13693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Sub8, False, 1, delta, "cmp" );
13695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x39: /* CMP Gv,Ev */
13697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Sub8, False, sz, delta, "cmp" );
13699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ POP ------------------------ */
13702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x58: /* POP eAX */
13704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x59: /* POP eCX */
13705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5A: /* POP eDX */
13706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5B: /* POP eBX */
13707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5D: /* POP eBP */
13708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5E: /* POP eSI */
13709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5F: /* POP eDI */
13710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5C: /* POP eSP */
13711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
13712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
13713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, getIReg(4, R_ESP));
13714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
13715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
13716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, opc-0x58, mkexpr(t1));
13717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
13718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9D: /* POPF */
13721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
13722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, getIReg(4, R_ESP));
13724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
13725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
13726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Generate IR to set %EFLAGS{O,S,Z,A,C,P,D,ID,AC} from the
13728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 value in t1. */
13729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      set_EFLAGS_from_value( t1, True/*emit_AC_emwarn*/,
13730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 ((Addr32)guest_EIP_bbstart)+delta );
13731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("popf%c\n", nameISize(sz));
13733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x61: /* POPA */
13736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is almost certainly wrong for sz==2.  So ... */
13737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4) goto decode_failure;
13738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t5 is the old %ESP value. */
13740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t5 = newTemp(Ity_I32);
13741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t5, getIReg(4, R_ESP) );
13742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Reload all the registers, except %esp. */
13744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
13745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
13746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
13747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
13748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ignore saved %ESP */
13749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
13750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
13751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
13752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* and move %ESP back up */
13754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
13755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("popa%c\n", nameISize(sz));
13757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8F: /* POPL/POPW m32 */
13760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     { Int    len;
13761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       UChar  rm = getIByte(delta);
13762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       /* make sure this instruction is correct POP */
13764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       if (epartIsReg(rm) || gregOfRM(rm) != 0)
13765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          goto decode_failure;
13766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       /* and has correct size */
13767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       if (sz != 4 && sz != 2)
13768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          goto decode_failure;
13769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ty = szToITy(sz);
13770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       t1 = newTemp(Ity_I32); /* stack address */
13772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       t3 = newTemp(ty); /* data */
13773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       /* set t1 to ESP: t1 = ESP */
13774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       assign( t1, getIReg(4, R_ESP) );
13775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       /* load M[ESP] to virtual register t3: t3 = M[t1] */
13776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       assign( t3, loadLE(ty, mkexpr(t1)) );
13777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       /* increase ESP; must be done before the STORE.  Intel manual says:
13779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            If the ESP register is used as a base register for addressing
13780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            a destination operand in memory, the POP instruction computes
13781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            the effective address of the operand after it increments the
13782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ESP register.
13783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       */
13784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
13785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       /* resolve MODR/M */
13787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       addr = disAMode ( &len, sorb, delta, dis_buf);
13788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       storeLE( mkexpr(addr), mkexpr(t3) );
13789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       DIP("pop%c %s\n", sz==2 ? 'w' : 'l', dis_buf);
13791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       delta += len;
13793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       break;
13794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
13795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1F: /* POP %DS */
13797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_pop_segreg( R_DS, sz ); break;
13798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x07: /* POP %ES */
13799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_pop_segreg( R_ES, sz ); break;
13800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x17: /* POP %SS */
13801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_pop_segreg( R_SS, sz ); break;
13802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ PUSH ----------------------- */
13804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x50: /* PUSH eAX */
13806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x51: /* PUSH eCX */
13807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x52: /* PUSH eDX */
13808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x53: /* PUSH eBX */
13809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x55: /* PUSH eBP */
13810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x56: /* PUSH eSI */
13811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x57: /* PUSH eDI */
13812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x54: /* PUSH eSP */
13813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is the Right Way, in that the value to be pushed is
13814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         established before %esp is changed, so that pushl %esp
13815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         correctly pushes the old value. */
13816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
13817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = sz==2 ? Ity_I16 : Ity_I32;
13818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(ty); t2 = newTemp(Ity_I32);
13819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIReg(sz, opc-0x50));
13820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
13821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, mkexpr(t2) );
13822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE(mkexpr(t2),mkexpr(t1));
13823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
13824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x68: /* PUSH Iv */
13828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getUDisp(sz,delta); delta += sz;
13829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_push_I;
13830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x6A: /* PUSH Ib, sign-extended to sz */
13831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getSDisp8(delta); delta += 1;
13832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_push_I;
13833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_push_I:
13834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
13835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32); t2 = newTemp(ty);
13836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
13837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, mkexpr(t1) );
13838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* stop mkU16 asserting if d32 is a negative 16-bit number
13839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (bug #132813) */
13840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ty == Ity_I16)
13841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 &= 0xFFFF;
13842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(t1), mkU(ty,d32) );
13843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("push%c $0x%x\n", nameISize(sz), d32);
13844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9C: /* PUSHF */ {
13847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
13848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
13850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
13851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, mkexpr(t1) );
13852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Calculate OSZACP, and patch in fixed fields as per
13854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Intel docs.
13855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         - bit 1 is always 1
13856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         - bit 9 is Interrupt Enable (should always be 1 in user mode?)
13857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
13858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I32);
13859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t2, binop(Iop_Or32,
13860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mk_x86g_calculate_eflags_all(),
13861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32( (1<<1)|(1<<9) ) ));
13862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Patch in the D flag.  This can simply be a copy of bit 10 of
13864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         baseBlock[OFFB_DFLAG]. */
13865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t3 = newTemp(Ity_I32);
13866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t3, binop(Iop_Or32,
13867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(t2),
13868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And32,
13869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              IRExpr_Get(OFFB_DFLAG,Ity_I32),
13870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(1<<10)))
13871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
13872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* And patch in the ID flag. */
13874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t4 = newTemp(Ity_I32);
13875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t4, binop(Iop_Or32,
13876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(t3),
13877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And32,
13878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
13879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               mkU8(21)),
13880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(1<<21)))
13881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
13882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* And patch in the AC flag. */
13884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t5 = newTemp(Ity_I32);
13885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t5, binop(Iop_Or32,
13886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(t4),
13887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And32,
13888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl32, IRExpr_Get(OFFB_ACFLAG,Ity_I32),
13889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               mkU8(18)),
13890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(1<<18)))
13891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
13892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* if sz==2, the stored value needs to be narrowed. */
13894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2)
13895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t5)) );
13896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
13897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        storeLE( mkexpr(t1), mkexpr(t5) );
13898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("pushf%c\n", nameISize(sz));
13900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x60: /* PUSHA */
13904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is almost certainly wrong for sz==2.  So ... */
13905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4) goto decode_failure;
13906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is the Right Way, in that the value to be pushed is
13908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         established before %esp is changed, so that pusha
13909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         correctly pushes the old %esp value.  New value of %esp is
13910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pushed at start. */
13911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t0 is the %ESP value we're going to push. */
13912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I32);
13913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, getIReg(4, R_ESP) );
13914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t5 will be the new %ESP value. */
13916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t5 = newTemp(Ity_I32);
13917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
13918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Update guest state before prodding memory. */
13920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, mkexpr(t5));
13921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Dump all the registers. */
13923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
13924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
13925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
13926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
13927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
13928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
13929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
13930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
13931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("pusha%c\n", nameISize(sz));
13933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0E: /* PUSH %CS */
13936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_push_segreg( R_CS, sz ); break;
13937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1E: /* PUSH %DS */
13938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_push_segreg( R_DS, sz ); break;
13939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x06: /* PUSH %ES */
13940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_push_segreg( R_ES, sz ); break;
13941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x16: /* PUSH %SS */
13942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_push_segreg( R_SS, sz ); break;
13943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ SCAS et al ----------------- */
13945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA4: /* MOVS, no REP prefix */
13947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA5:
13948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sorb != 0)
13949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure; /* else dis_string_op asserts */
13950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
13951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  case 0xA6: /* CMPSb, no REP prefix */
13954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  case 0xA7:
13955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sorb != 0)
13956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure; /* else dis_string_op asserts */
13957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
13958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAA: /* STOS, no REP prefix */
13961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAB:
13962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sorb != 0)
13963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure; /* else dis_string_op asserts */
13964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
13965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAC: /* LODS, no REP prefix */
13968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAD:
13969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sorb != 0)
13970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure; /* else dis_string_op asserts */
13971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
13972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAE: /* SCAS, no REP prefix */
13975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAF:
13976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sorb != 0)
13977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure; /* else dis_string_op asserts */
13978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
13979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xFC: /* CLD */
13983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
13984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cld\n");
13985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xFD: /* STD */
13988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
13989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("std\n");
13990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF8: /* CLC */
13993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF9: /* STC */
13994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF5: /* CMC */
13995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I32);
13996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
13997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, mk_x86g_calculate_eflags_all() );
13998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (opc) {
13999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF8:
14000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, binop(Iop_And32, mkexpr(t0),
14001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU32(~X86G_CC_MASK_C)));
14002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("clc\n");
14003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
14004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF9:
14005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, binop(Iop_Or32, mkexpr(t0),
14006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        mkU32(X86G_CC_MASK_C)));
14007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("stc\n");
14008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
14009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF5:
14010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, binop(Iop_Xor32, mkexpr(t0),
14011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU32(X86G_CC_MASK_C)));
14012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("cmc\n");
14013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
14014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
14015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("disInstr(x86)(clc/stc/cmc)");
14016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
14018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
14020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Set NDEP even though it isn't used.  This makes redundant-PUT
14021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         elimination of previous stores to this field work better. */
14022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD6: /* SALC */
14026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I32);
14027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0,  binop(Iop_And32,
14029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mk_x86g_calculate_eflags_c(),
14030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU32(1)) );
14031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop(Iop_Sar32,
14032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl32, mkexpr(t0), mkU8(31)),
14033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(31)) );
14034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(1, R_EAX, unop(Iop_32to8, mkexpr(t1)) );
14035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("salc\n");
14036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* REPNE prefix insn */
14039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF2: {
14040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr32 eip_orig = guest_EIP_bbstart + delta_start;
14041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sorb != 0) goto decode_failure;
14042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getIByte(delta); delta++;
14043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
14045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (abyte) {
14047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* According to the Intel manual, "repne movs" should never occur, but
14048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * in practice it has happened, so allow for it here... */
14049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA4: sz = 1;   /* REPNE MOVS<sz> */
14050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA5:
14051663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondNZ, dis_MOVS, sz, eip_orig,
14052663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "repne movs" );
14053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA6: sz = 1;   /* REPNE CMP<sz> */
14056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA7:
14057663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondNZ, dis_CMPS, sz, eip_orig,
14058663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "repne cmps" );
14059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAA: sz = 1;   /* REPNE STOS<sz> */
14062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAB:
14063663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondNZ, dis_STOS, sz, eip_orig,
14064663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "repne stos" );
14065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAE: sz = 1;   /* REPNE SCAS<sz> */
14068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAF:
14069663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondNZ, dis_SCAS, sz, eip_orig,
14070663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "repne scas" );
14071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
14074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
14080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for the rest, it means REP) */
14081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF3: {
14082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr32 eip_orig = guest_EIP_bbstart + delta_start;
14083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getIByte(delta); delta++;
14084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
14086663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
14087663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (sorb != 0 && abyte != 0x0F) goto decode_failure;
14088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (abyte) {
14090663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      case 0x0F:
14091663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         switch (getIByte(delta)) {
14092663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         /* On older CPUs, TZCNT behaves the same as BSF.  */
14093663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         case 0xBC: /* REP BSF Gv,Ev */
14094663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            delta = dis_bs_E_G ( sorb, sz, delta + 1, True );
14095663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            break;
14096663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         /* On older CPUs, LZCNT behaves the same as BSR.  */
14097663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         case 0xBD: /* REP BSR Gv,Ev */
14098663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            delta = dis_bs_E_G ( sorb, sz, delta + 1, False );
14099663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            break;
14100663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         default:
14101663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            goto decode_failure;
14102663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         }
14103663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         break;
14104663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
14105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA4: sz = 1;   /* REP MOVS<sz> */
14106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA5:
14107663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondAlways, dis_MOVS, sz, eip_orig,
14108663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "rep movs" );
14109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA6: sz = 1;   /* REPE CMP<sz> */
14112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA7:
14113663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondZ, dis_CMPS, sz, eip_orig,
14114663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "repe cmps" );
14115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAA: sz = 1;   /* REP STOS<sz> */
14118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAB:
14119663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondAlways, dis_STOS, sz, eip_orig,
14120663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "rep stos" );
14121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAC: sz = 1;   /* REP LODS<sz> */
14124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAD:
14125663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondAlways, dis_LODS, sz, eip_orig,
14126663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "rep lods" );
14127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAE: sz = 1;   /* REPE SCAS<sz> */
14130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAF:
14131663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondZ, dis_SCAS, sz, eip_orig,
14132663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "repe scas" );
14133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x90:           /* REP NOP (PAUSE) */
14136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* a hint to the P4 re spin-wait loop */
14137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("rep nop (P4 pause)\n");
14138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* "observe" the hint.  The Vex client needs to be careful not
14139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            to cause very long delays as a result, though. */
14140663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Yield, ((Addr32)guest_EIP_bbstart)+delta);
14141663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
14142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC3:           /* REP RET -- same as normal ret? */
14145663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_ret(&dres, 0);
14146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("rep ret\n");
14147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
14150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ XCHG ----------------------- */
14156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* XCHG reg,mem automatically asserts LOCK# even without a LOCK
14158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      prefix; hence it must be translated with an IRCAS (at least, the
14159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      memory variant). */
14160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x86: /* XCHG Gb,Eb */
14161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
14162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Fall through ... */
14163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x87: /* XCHG Gv,Ev */
14164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
14166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(ty); t2 = newTemp(ty);
14167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
14168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t1, getIReg(sz, eregOfRM(modrm)));
14169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t2, getIReg(sz, gregOfRM(modrm)));
14170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(sz, gregOfRM(modrm), mkexpr(t1));
14171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(sz, eregOfRM(modrm), mkexpr(t2));
14172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
14173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("xchg%c %s, %s\n",
14174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
14175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameIReg(sz,eregOfRM(modrm)));
14176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *expect_CAS = True;
14178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
14179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t1, loadLE(ty,mkexpr(addr)) );
14180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2, getIReg(sz,gregOfRM(modrm)) );
14181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         casLE( mkexpr(addr),
14182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
14183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
14184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
14185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("xchg%c %s, %s\n", nameISize(sz),
14186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameIReg(sz,gregOfRM(modrm)), dis_buf);
14187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x90: /* XCHG eAX,eAX */
14191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("nop\n");
14192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x91: /* XCHG eAX,eCX */
14194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x92: /* XCHG eAX,eDX */
14195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x93: /* XCHG eAX,eBX */
14196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x94: /* XCHG eAX,eSP */
14197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x95: /* XCHG eAX,eBP */
14198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x96: /* XCHG eAX,eSI */
14199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x97: /* XCHG eAX,eDI */
14200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
14201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ XLAT ----------------------- */
14204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD7: /* XLAT */
14206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4) goto decode_failure; /* sz == 2 is also allowed (0x66) */
14207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(
14208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         1,
14209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         R_EAX/*AL*/,
14210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         loadLE(Ity_I8,
14211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                handleSegOverride(
14212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   sorb,
14213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_Add32,
14214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         getIReg(4, R_EBX),
14215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         unop(Iop_8Uto32, getIReg(1, R_EAX/*AL*/))))));
14216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("xlat%c [ebx]\n", nameISize(sz));
14218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ IN / OUT ----------------------- */
14221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE4: /* IN imm8, AL */
14223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
14224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getIByte(delta); delta++;
14226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, mkU32( abyte & 0xFF ));
14227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX));
14228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_IN;
14229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE5: /* IN imm8, eAX */
14230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
14231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getIByte(delta); delta++;
14233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, mkU32( abyte & 0xFF ));
14234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX));
14235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_IN;
14236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xEC: /* IN %DX, AL */
14237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
14238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         nameIReg(sz,R_EAX));
14242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_IN;
14243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xED: /* IN %DX, eAX */
14244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
14245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         nameIReg(sz,R_EAX));
14249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_IN;
14250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_IN: {
14251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* At this point, sz indicates the width, and t1 is a 32-bit
14252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         value giving port number. */
14253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRDirty* d;
14254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 1 || sz == 2 || sz == 4);
14255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
14256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I32);
14257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d = unsafeIRDirty_1_N(
14258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             t2,
14259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             0/*regparms*/,
14260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             "x86g_dirtyhelper_IN",
14261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             &x86g_dirtyhelper_IN,
14262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkIRExprVec_2( mkexpr(t1), mkU32(sz) )
14263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
14264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* do the call, dumping the result in t2. */
14265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Dirty(d) );
14266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, R_EAX, narrowTo( ty, mkexpr(t2) ) );
14267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE6: /* OUT AL, imm8 */
14271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
14272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getIByte(delta); delta++;
14274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, mkU32( abyte & 0xFF ) );
14275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte);
14276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_OUT;
14277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE7: /* OUT eAX, imm8 */
14278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
14279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getIByte(delta); delta++;
14281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, mkU32( abyte & 0xFF ) );
14282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte);
14283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_OUT;
14284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xEE: /* OUT AL, %DX */
14285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
14286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          nameIReg(2,R_EDX));
14290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_OUT;
14291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xEF: /* OUT eAX, %DX */
14292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
14293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          nameIReg(2,R_EDX));
14297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_OUT;
14298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_OUT: {
14299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* At this point, sz indicates the width, and t1 is a 32-bit
14300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         value giving port number. */
14301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRDirty* d;
14302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 1 || sz == 2 || sz == 4);
14303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
14304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d = unsafeIRDirty_0_N(
14305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             0/*regparms*/,
14306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             "x86g_dirtyhelper_OUT",
14307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             &x86g_dirtyhelper_OUT,
14308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkIRExprVec_3( mkexpr(t1),
14309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            widenUto32( getIReg(sz, R_EAX) ),
14310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(sz) )
14311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
14312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Dirty(d) );
14313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp1 extensions) ---------- */
14317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x82: /* Grp1 Ib,Eb too.  Apparently this is the same as
14319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 case 0x80, but only in 32-bit mode. */
14320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fallthru */
14321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x80: /* Grp1 Ib,Eb */
14322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz    = 1;
14325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 1;
14326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = getUChar(delta + am_sz);
14327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
14328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x81: /* Grp1 Iv,Ev */
14331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = sz;
14334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = getUDisp(d_sz, delta + am_sz);
14335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
14336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x83: /* Grp1 Ib,Ev */
14339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 1;
14342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = getSDisp8(delta + am_sz);
14343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
14344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp2 extensions) ---------- */
14347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC0: { /* Grp2 Ib,Eb */
14349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 1;
14353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = getUChar(delta + am_sz);
14354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz    = 1;
14355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(d32 & 0xFF), NULL, &decode_OK );
14357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC1: { /* Grp2 Ib,Ev */
14362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 1;
14366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = getUChar(delta + am_sz);
14367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(d32 & 0xFF), NULL, &decode_OK );
14369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD0: { /* Grp2 1,Eb */
14374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 0;
14378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = 1;
14379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz    = 1;
14380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(d32), NULL, &decode_OK );
14382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD1: { /* Grp2 1,Ev */
14387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
14389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 0;
14391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = 1;
14392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(d32), NULL, &decode_OK );
14394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD2: { /* Grp2 CL,Eb */
14399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
14401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 0;
14403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz    = 1;
14404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         getIReg(1,R_ECX), "%cl", &decode_OK );
14406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD3: { /* Grp2 CL,Ev */
14411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 0;
14415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         getIReg(1,R_ECX), "%cl", &decode_OK );
14417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp3 extensions) ---------- */
14423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF6: { /* Grp3 Eb */
14425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp3 ( sorb, pfx_lock, 1, delta, &decode_OK );
14427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF7: { /* Grp3 Ev */
14432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp3 ( sorb, pfx_lock, sz, delta, &decode_OK );
14434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp4 extensions) ---------- */
14440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xFE: { /* Grp4 Eb */
14442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp4 ( sorb, pfx_lock, delta, &decode_OK );
14444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp5 extensions) ---------- */
14450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xFF: { /* Grp5 Ev */
14452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp5 ( sorb, pfx_lock, sz, delta, &dres, &decode_OK );
14454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ Escapes to 2-byte opcodes -- */
14460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0F: {
14462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      opc = getIByte(delta); delta++;
14463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (opc) {
14464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
14466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBA: { /* Grp8 Ib,Ev */
14468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool decode_OK = False;
14469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
14470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         am_sz = lengthAMode(delta);
14471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32   = getSDisp8(delta + am_sz);
14472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_Grp8_Imm ( sorb, pfx_lock, delta, modrm,
14473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                am_sz, sz, d32, &decode_OK );
14474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!decode_OK)
14475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
14476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
14480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBC: /* BSF Gv,Ev */
14482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bs_E_G ( sorb, sz, delta, True );
14483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBD: /* BSR Gv,Ev */
14485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bs_E_G ( sorb, sz, delta, False );
14486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
14489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC8: /* BSWAP %eax */
14491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC9:
14492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCA:
14493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCB:
14494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCC:
14495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCD:
14496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCE:
14497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCF: /* BSWAP %edi */
14498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* AFAICS from the Intel docs, this only exists at size 4. */
14499663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         if (sz != 4) goto decode_failure;
14500663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
14501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I32);
14502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t1, getIReg(4, opc-0xC8) );
14503663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         t2 = math_BSWAP(t1, Ity_I32);
14504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, opc-0xC8, mkexpr(t2));
14506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
14507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
14510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA3: /* BT Gv,Ev */
14512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpNone );
14513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB3: /* BTR Gv,Ev */
14515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpReset );
14516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAB: /* BTS Gv,Ev */
14518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpSet );
14519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBB: /* BTC Gv,Ev */
14521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpComp );
14522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
14525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x40:
14527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x41:
14528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
14529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
14530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
14531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
14532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
14533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
14534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x48: /* CMOVSb (cmov negative) */
14535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x49: /* CMOVSb (cmov not negative) */
14536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4A: /* CMOVP (cmov parity even) */
14537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4B: /* CMOVNP (cmov parity odd) */
14538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
14539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
14540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
14541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
14542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
14543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
14546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB0: /* CMPXCHG Gb,Eb */
14548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_cmpxchg_G_E ( sorb, pfx_lock, 1, delta );
14549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB1: /* CMPXCHG Gv,Ev */
14551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_cmpxchg_G_E ( sorb, pfx_lock, sz, delta );
14552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC7: { /* CMPXCHG8B Gv (0F C7 /1) */
14555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp expdHi    = newTemp(Ity_I32);
14556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp expdLo    = newTemp(Ity_I32);
14557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp dataHi    = newTemp(Ity_I32);
14558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp dataLo    = newTemp(Ity_I32);
14559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldHi     = newTemp(Ity_I32);
14560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldLo     = newTemp(Ity_I32);
14561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp flags_old = newTemp(Ity_I32);
14562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp flags_new = newTemp(Ity_I32);
14563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp success   = newTemp(Ity_I1);
14564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Translate this using a DCAS, even if there is no LOCK
14566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            prefix.  Life is too short to bother with generating two
14567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            different translations for the with/without-LOCK-prefix
14568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            cases. */
14569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *expect_CAS = True;
14570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* Decode, and generate address. */
14572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4) goto decode_failure;
14573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
14574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) goto decode_failure;
14575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregOfRM(modrm) != 1) goto decode_failure;
14576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
14577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
14578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Get the expected and new values. */
14580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( expdHi, getIReg(4,R_EDX) );
14581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( expdLo, getIReg(4,R_EAX) );
14582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dataHi, getIReg(4,R_ECX) );
14583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dataLo, getIReg(4,R_EBX) );
14584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Do the DCAS */
14586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_CAS(
14587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkIRCAS( oldHi, oldLo,
14588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Iend_LE, mkexpr(addr),
14589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(expdHi), mkexpr(expdLo),
14590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(dataHi), mkexpr(dataLo)
14591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )));
14592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* success when oldHi:oldLo == expdHi:expdLo */
14594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( success,
14595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_CasCmpEQ32,
14596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Or32,
14597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Xor32, mkexpr(oldHi), mkexpr(expdHi)),
14598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Xor32, mkexpr(oldLo), mkexpr(expdLo))
14599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       ),
14600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(0)
14601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 ));
14602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If the DCAS is successful, that is to say oldHi:oldLo ==
14604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            expdHi:expdLo, then put expdHi:expdLo back in EDX:EAX,
14605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            which is where they came from originally.  Both the actual
14606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            contents of these two regs, and any shadow values, are
14607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unchanged.  If the DCAS fails then we're putting into
14608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            EDX:EAX the value seen in memory. */
14609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EDX,
14610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(success)),
14611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkexpr(oldHi),
14612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkexpr(expdHi)
14613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ));
14614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EAX,
14615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(success)),
14616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkexpr(oldLo),
14617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkexpr(expdLo)
14618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ));
14619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Copy the success bit into the Z flag and leave the others
14621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unchanged */
14622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( flags_old, widenUto32(mk_x86g_calculate_eflags_all()));
14623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(
14624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            flags_new,
14625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Or32,
14626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_And32, mkexpr(flags_old),
14627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU32(~X86G_CC_MASK_Z)),
14628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Shl32,
14629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And32,
14630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_1Uto32, mkexpr(success)), mkU32(1)),
14631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(X86G_CC_SHIFT_Z)) ));
14632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
14634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
14635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Set NDEP even though it isn't used.  This makes
14637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            redundant-PUT elimination of previous stores to this field
14638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            work better. */
14639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Sheesh.  Aren't you glad it was me and not you that had to
14642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    write and validate all this grunge? */
14643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 DIP("cmpxchg8b %s\n", dis_buf);
14645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 break;
14646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
14649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA2: { /* CPUID */
14651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Uses dirty helper:
14652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               void dirtyhelper_CPUID_sse[012] ( VexGuestX86State* )
14653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            declared to mod eax, wr ebx, ecx, edx
14654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
14655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRDirty* d     = NULL;
14656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar*   fName = NULL;
14657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         void*    fAddr = NULL;
14658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2) {
14659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fName = "x86g_dirtyhelper_CPUID_sse2";
14660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fAddr = &x86g_dirtyhelper_CPUID_sse2;
14661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
14663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE1) {
14664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fName = "x86g_dirtyhelper_CPUID_sse1";
14665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fAddr = &x86g_dirtyhelper_CPUID_sse1;
14666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
14668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (archinfo->hwcaps == 0/*no SSE*/) {
14669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fName = "x86g_dirtyhelper_CPUID_sse0";
14670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fAddr = &x86g_dirtyhelper_CPUID_sse0;
14671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else
14672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("disInstr(x86)(cpuid)");
14673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(fName); vassert(fAddr);
14675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d = unsafeIRDirty_0_N ( 0/*regparms*/,
14676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 fName, fAddr, mkIRExprVec_0() );
14677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* declare guest state effects */
14678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->needsBBP = True;
14679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->nFxState = 4;
14680663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vex_bzero(&d->fxState, sizeof(d->fxState));
14681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[0].fx     = Ifx_Modify;
14682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[0].offset = OFFB_EAX;
14683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[0].size   = 4;
14684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[1].fx     = Ifx_Write;
14685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[1].offset = OFFB_EBX;
14686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[1].size   = 4;
14687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[2].fx     = Ifx_Modify;
14688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[2].offset = OFFB_ECX;
14689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[2].size   = 4;
14690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[3].fx     = Ifx_Write;
14691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[3].offset = OFFB_EDX;
14692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[3].size   = 4;
14693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* execute the dirty call, side-effecting guest state */
14694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Dirty(d) );
14695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* CPUID is a serialising insn.  So, just in case someone is
14696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            using it as a memory fence ... */
14697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_MBE(Imbe_Fence) );
14698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cpuid\n");
14699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
14703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--             goto decode_failure;
14704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          t1 = newTemp(cb);
14706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          t2 = newTemp(cb);
14707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          t3 = newTemp(cb);
14708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          t4 = newTemp(cb);
14709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr0(cb, CALLM_S, 0);
14710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, GET,   4, ArchReg, R_EAX, TempReg, t1);
14712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, PUSH,  4, TempReg, t1);
14713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, MOV,   4, Literal, 0, TempReg, t2);
14715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uLiteral(cb, 0);
14716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, PUSH,  4, TempReg, t2);
14717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, MOV,   4, Literal, 0, TempReg, t3);
14719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uLiteral(cb, 0);
14720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, PUSH,  4, TempReg, t3);
14721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, MOV,   4, Literal, 0, TempReg, t4);
14723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uLiteral(cb, 0);
14724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, PUSH,  4, TempReg, t4);
14725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, CALLM, 0, Lit16,   VGOFF_(helper_CPUID));
14727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
14728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, POP,   4, TempReg, t4);
14730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, PUT,   4, TempReg, t4, ArchReg, R_EDX);
14731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, POP,   4, TempReg, t3);
14733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, PUT,   4, TempReg, t3, ArchReg, R_ECX);
14734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, POP,   4, TempReg, t2);
14736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, PUT,   4, TempReg, t2, ArchReg, R_EBX);
14737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, POP,   4, TempReg, t1);
14739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, PUT,   4, TempReg, t1, ArchReg, R_EAX);
14740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr0(cb, CALLM_E, 0);
14742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          DIP("cpuid\n");
14743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          break;
14744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
14746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB6: /* MOVZXb Eb,Gv */
14748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 2 && sz != 4)
14749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
14750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_movx_E_G ( sorb, delta, 1, sz, False );
14751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB7: /* MOVZXw Ew,Gv */
14754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
14755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
14756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
14757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBE: /* MOVSXb Eb,Gv */
14760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 2 && sz != 4)
14761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
14762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_movx_E_G ( sorb, delta, 1, sz, True );
14763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBF: /* MOVSXw Ew,Gv */
14766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4 && /* accept movsww, sigh, see #250799 */sz != 2)
14767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
14768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_movx_E_G ( sorb, delta, 2, sz, True );
14769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
14772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       case 0xC3: /* MOVNTI Gv,Ev */
14774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          vg_assert(sz == 4);
14775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          modrm = getUChar(eip);
14776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          vg_assert(!epartIsReg(modrm));
14777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          t1 = newTemp(cb);
14778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
14779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          pair = disAMode ( cb, sorb, eip, dis_buf );
14780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          t2 = LOW24(pair);
14781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          eip += HI8(pair);
14782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
14783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
14784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          break;
14785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
14787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAF: /* IMUL Ev, Gv */
14789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_mul_E_G ( sorb, sz, delta );
14790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
14793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x1F:
14795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
14796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) goto decode_failure;
14797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
14798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
14799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("nop%c %s\n", nameISize(sz), dis_buf);
14800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
14803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x80:
14804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x81:
14805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x82: /* JBb/JNAEb (jump below) */
14806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x83: /* JNBb/JAEb (jump not below) */
14807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x84: /* JZb/JEb (jump zero) */
14808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x85: /* JNZb/JNEb (jump not zero) */
14809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x86: /* JBEb/JNAb (jump below or equal) */
14810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x87: /* JNBEb/JAb (jump not below or equal) */
14811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x88: /* JSb (jump negative) */
14812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x89: /* JSb (jump not negative) */
14813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8A: /* JP (jump parity even) */
14814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8B: /* JNP/JPO (jump parity odd) */
14815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8C: /* JLb/JNGEb (jump less) */
14816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8D: /* JGEb/JNLb (jump greater or equal) */
14817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8E: /* JLEb/JNGb (jump less or equal) */
14818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8F: /* JGb/JNLEb (jump greater) */
14819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       { Int    jmpDelta;
14820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* comment  = "";
14821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         jmpDelta = (Int)getUDisp32(delta);
14822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 = (((Addr32)guest_EIP_bbstart)+delta+4) + jmpDelta;
14823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4;
14824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (resteerCisOk
14825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && vex_control.guest_chase_cond
14826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && (Addr32)d32 != (Addr32)guest_EIP_bbstart
14827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && jmpDelta < 0
14828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
14829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Speculation: assume this backward branch is taken.  So
14830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               we need to emit a side-exit to the insn following this
14831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               one, on the negation of the condition, and continue at
14832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               the branch target address (d32).  If we wind up back at
14833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               the first instruction of the trace, just stop; it's
14834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               better to let the IR loop unroller handle that case.*/
14835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_Exit(
14836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mk_x86g_calculate_condition((X86Condcode)
14837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                 (1 ^ (opc - 0x80))),
14838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_Boring,
14839663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     IRConst_U32(guest_EIP_bbstart+delta),
14840663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     OFFB_EIP ) );
14841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext   = Dis_ResteerC;
14842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.continueAt = (Addr64)(Addr32)d32;
14843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            comment = "(assumed taken)";
14844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
14846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (resteerCisOk
14847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && vex_control.guest_chase_cond
14848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && (Addr32)d32 != (Addr32)guest_EIP_bbstart
14849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && jmpDelta >= 0
14850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && resteerOkFn( callback_opaque,
14851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             (Addr64)(Addr32)(guest_EIP_bbstart+delta)) ) {
14852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Speculation: assume this forward branch is not taken.
14853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               So we need to emit a side-exit to d32 (the dest) and
14854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               continue disassembling at the insn immediately
14855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               following this one. */
14856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_Exit(
14857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mk_x86g_calculate_condition((X86Condcode)(opc - 0x80)),
14858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_Boring,
14859663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     IRConst_U32(d32),
14860663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     OFFB_EIP ) );
14861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext   = Dis_ResteerC;
14862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.continueAt = (Addr64)(Addr32)(guest_EIP_bbstart+delta);
14863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            comment = "(assumed not taken)";
14864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else {
14866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Conservative default translation - end the block at
14867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               this point. */
14868663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jcc_01( &dres, (X86Condcode)(opc - 0x80),
14869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    (Addr32)(guest_EIP_bbstart+delta), d32);
14870663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres.whatNext == Dis_StopHere);
14871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("j%s-32 0x%x %s\n", name_X86Condcode(opc - 0x80), d32, comment);
14873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       }
14875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
14877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x31: { /* RDTSC */
14878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp   val  = newTemp(Ity_I64);
14879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr** args = mkIRExprVec_0();
14880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRDirty* d    = unsafeIRDirty_1_N (
14881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            val,
14882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            0/*regparms*/,
14883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            "x86g_dirtyhelper_RDTSC",
14884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            &x86g_dirtyhelper_RDTSC,
14885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            args
14886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         );
14887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* execute the dirty call, dumping the result in val. */
14888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Dirty(d) );
14889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EDX, unop(Iop_64HIto32, mkexpr(val)));
14890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EAX, unop(Iop_64to32, mkexpr(val)));
14891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("rdtsc\n");
14892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
14896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA1: /* POP %FS */
14898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_pop_segreg( R_FS, sz ); break;
14899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA9: /* POP %GS */
14900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_pop_segreg( R_GS, sz ); break;
14901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA0: /* PUSH %FS */
14903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_push_segreg( R_FS, sz ); break;
14904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA8: /* PUSH %GS */
14905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_push_segreg( R_GS, sz ); break;
14906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
14908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x90:
14909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x91:
14910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x92: /* set-Bb/set-NAEb (jump below) */
14911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x93: /* set-NBb/set-AEb (jump not below) */
14912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x94: /* set-Zb/set-Eb (jump zero) */
14913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x95: /* set-NZb/set-NEb (jump not zero) */
14914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x96: /* set-BEb/set-NAb (jump below or equal) */
14915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
14916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x98: /* set-Sb (jump negative) */
14917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x99: /* set-Sb (jump not negative) */
14918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9A: /* set-P (jump parity even) */
14919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9B: /* set-NP (jump parity odd) */
14920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9C: /* set-Lb/set-NGEb (jump less) */
14921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
14922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
14923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9F: /* set-Gb/set-NLEb (jump greater) */
14924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I8);
14925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
14926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
14927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
14928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
14929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(1, eregOfRM(modrm), mkexpr(t1));
14930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("set%s %s\n", name_X86Condcode(opc-0x90),
14931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameIReg(1,eregOfRM(modrm)));
14932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
14933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           addr = disAMode ( &alen, sorb, delta, dis_buf );
14934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           delta += alen;
14935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           storeLE( mkexpr(addr), mkexpr(t1) );
14936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
14937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
14941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA4: /* SHLDv imm8,Gv,Ev */
14943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
14944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32   = delta + lengthAMode(delta);
14945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_sprintf(dis_buf, "$%d", getIByte(d32));
14946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_SHLRD_Gv_Ev (
14947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  sorb, delta, modrm, sz,
14948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU8(getIByte(d32)), True, /* literal */
14949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  dis_buf, True );
14950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA5: /* SHLDv %cl,Gv,Ev */
14952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
14953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_SHLRD_Gv_Ev (
14954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    sorb, delta, modrm, sz,
14955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getIReg(1,R_ECX), False, /* not literal */
14956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "%cl", True );
14957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAC: /* SHRDv imm8,Gv,Ev */
14960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
14961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32   = delta + lengthAMode(delta);
14962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_sprintf(dis_buf, "$%d", getIByte(d32));
14963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_SHLRD_Gv_Ev (
14964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    sorb, delta, modrm, sz,
14965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(getIByte(d32)), True, /* literal */
14966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    dis_buf, False );
14967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAD: /* SHRDv %cl,Gv,Ev */
14969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
14970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_SHLRD_Gv_Ev (
14971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    sorb, delta, modrm, sz,
14972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getIReg(1,R_ECX), False, /* not literal */
14973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "%cl", False );
14974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- SYSENTER -=-=-=-=-=-=-=-=-=-= */
14977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x34:
14979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Simple implementation needing a long explaination.
14980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sysenter is a kind of syscall entry.  The key thing here
14982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            is that the return address is not known -- that is
14983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            something that is beyond Vex's knowledge.  So this IR
14984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            forces a return to the scheduler, which can do what it
14985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            likes to simulate the systenter, but it MUST set this
14986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            thread's guest_EIP field with the continuation address
14987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            before resuming execution.  If that doesn't happen, the
14988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            thread will jump to address zero, which is probably
14989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fatal.
14990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
14991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Note where we are, so we can back up the guest to this
14993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            point if the syscall needs to be restarted. */
14994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
14995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32(guest_EIP_curr_instr) ) );
14996663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Sys_sysenter, 0/*bogus next EIP value*/);
14997663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
14998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("sysenter");
14999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
15002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC0: { /* XADD Gb,Eb */
15004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool decodeOK;
15005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_xadd_G_E ( sorb, pfx_lock, 1, delta, &decodeOK );
15006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!decodeOK) goto decode_failure;
15007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC1: { /* XADD Gv,Ev */
15010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool decodeOK;
15011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_xadd_G_E ( sorb, pfx_lock, sz, delta, &decodeOK );
15012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!decodeOK) goto decode_failure;
15013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
15017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x71:
15019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x72:
15020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
15021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
15023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
15024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
15025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
15026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFC:
15028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFD:
15029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
15030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEC:
15032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
15033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDC:
15035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
15036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF8:
15038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF9:
15039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
15040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE8:
15042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
15043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD8:
15045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
15046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
15048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
15049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
15051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x74:
15053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x75:
15054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
15055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x64:
15057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x65:
15058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
15059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
15061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
15062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
15063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x68:
15065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x69:
15066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
15067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x60:
15069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x61:
15070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
15071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
15073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
15074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
15075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
15076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
15078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF2:
15079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF3:
15080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
15082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD2:
15083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD3:
15084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
15086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE2:
15087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
15088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int  delta0    = delta-1;
15089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool decode_OK = False;
15090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If sz==2 this is SSE, and we assume sse idec has
15092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            already spotted those cases by now. */
15093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
15094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
15095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
15097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!decode_OK) {
15098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta = delta0;
15099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
15100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15104b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case 0x0E: /* FEMMS */
15105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x77: /* EMMS */
15106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
15107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
15108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_EMMS_preamble();
15109b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DIP("{f}emms\n");
15110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- SGDT and SIDT =-=-=-=-=-=-=-=-=-=-= */
15113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x01: /* 0F 01 /0 -- SGDT */
15114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 /* 0F 01 /1 -- SIDT */
15115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
15116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          /* This is really revolting, but ... since each processor
15117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (core) only has one IDT and one GDT, just let the guest
15118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             see it (pass-through semantics).  I can't see any way to
15119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             construct a faked-up value, so don't bother to try. */
15120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
15121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
15122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
15123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) goto decode_failure;
15124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)
15125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
15126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
15127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: DIP("sgdt %s\n", dis_buf); break;
15128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: DIP("sidt %s\n", dis_buf); break;
15129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0); /*NOTREACHED*/
15130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRDirty* d = unsafeIRDirty_0_N (
15133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          0/*regparms*/,
15134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "x86g_dirtyhelper_SxDT",
15135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          &x86g_dirtyhelper_SxDT,
15136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkIRExprVec_2( mkexpr(addr),
15137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU32(gregOfRM(modrm)) )
15138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      );
15139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* declare we're writing memory */
15140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->mFx   = Ifx_Write;
15141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->mAddr = mkexpr(addr);
15142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->mSize = 6;
15143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Dirty(d) );
15144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
15148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
15150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
15151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* switch (opc) for the 2-byte opcodes */
15152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   goto decode_success;
15153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* case 0x0F: of primary opcode */
15154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ ??? ------------------------ */
15156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  default:
15158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_failure:
15159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* All decode failures end up here. */
15160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf("vex x86->IR: unhandled instruction bytes: "
15161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              "0x%x 0x%x 0x%x 0x%x\n",
15162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (Int)getIByte(delta_start+0),
15163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (Int)getIByte(delta_start+1),
15164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (Int)getIByte(delta_start+2),
15165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (Int)getIByte(delta_start+3) );
15166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Tell the dispatcher that this insn cannot be decoded, and so has
15168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      not been executed, and (is currently) the next to be executed.
15169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      EIP should be up-to-date since it made so at the start of each
15170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      insn, but nevertheless be paranoid and update it again right
15171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      now. */
15172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr) ) );
15173663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   jmp_lit(&dres, Ijk_NoDecode, guest_EIP_curr_instr);
15174663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres.whatNext == Dis_StopHere);
15175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.len = 0;
15176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We also need to say that a CAS is not expected now, regardless
15177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of what it might have been set to at the start of the function,
15178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      since the IR that we've emitted just above (to synthesis a
15179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SIGILL) does not involve any CAS, and presumably no other IR has
15180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      been emitted for this (non-decoded) insn. */
15181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *expect_CAS = False;
15182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
15183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* switch (opc) for the main (primary) opcode switch. */
15185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_success:
15187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* All decode successes end up here. */
15188663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   switch (dres.whatNext) {
15189663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      case Dis_Continue:
15190663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_bbstart + delta) ) );
15191663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         break;
15192663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      case Dis_ResteerU:
15193663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      case Dis_ResteerC:
15194663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         stmt( IRStmt_Put( OFFB_EIP, mkU32(dres.continueAt) ) );
15195663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         break;
15196663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      case Dis_StopHere:
15197663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         break;
15198663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      default:
15199663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(0);
15200663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
15201663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
15202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("\n");
15203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.len = delta - delta_start;
15204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
15205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
15206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef DIP
15208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef DIS
15209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
15212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Top-level fn                                         ---*/
15213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
15214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Disassemble a single instruction into IR.  The instruction
15216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is located in host memory at &guest_code[delta]. */
15217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownDisResult disInstr_X86 ( IRSB*        irsb_IN,
15219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Bool         (*resteerOkFn) ( void*, Addr64 ),
15220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Bool         resteerCisOk,
15221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         void*        callback_opaque,
15222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         UChar*       guest_code_IN,
15223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Long         delta,
15224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Addr64       guest_IP,
15225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         VexArch      guest_arch,
15226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         VexArchInfo* archinfo,
15227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         VexAbiInfo*  abiinfo,
15228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Bool         host_bigendian_IN )
15229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
15230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int       i, x1, x2;
15231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool      expect_CAS, has_CAS;
15232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DisResult dres;
15233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set globals (see top of this file) */
15235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guest_arch == VexArchX86);
15236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest_code           = guest_code_IN;
15237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   irsb                 = irsb_IN;
15238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   host_is_bigendian    = host_bigendian_IN;
15239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest_EIP_curr_instr = (Addr32)guest_IP;
15240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest_EIP_bbstart    = (Addr32)toUInt(guest_IP - delta);
15241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x1 = irsb_IN->stmts_used;
15243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   expect_CAS = False;
15244663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
15245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             resteerCisOk,
15246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             callback_opaque,
15247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             delta, archinfo, abiinfo );
15248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x2 = irsb_IN->stmts_used;
15249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(x2 >= x1);
15250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* See comment at the top of disInstr_X86_WRK for meaning of
15252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      expect_CAS.  Here, we (sanity-)check for the presence/absence of
15253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRCAS as directed by the returned expect_CAS value. */
15254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   has_CAS = False;
15255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = x1; i < x2; i++) {
15256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (irsb_IN->stmts[i]->tag == Ist_CAS)
15257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         has_CAS = True;
15258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (expect_CAS != has_CAS) {
15261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* inconsistency detected.  re-disassemble the instruction so as
15262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to generate a useful error message; then assert. */
15263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_traceflags |= VEX_TRACE_FE;
15264663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
15265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                resteerCisOk,
15266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                callback_opaque,
15267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                delta, archinfo, abiinfo );
15268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = x1; i < x2; i++) {
15269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("\t\t");
15270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ppIRStmt(irsb_IN->stmts[i]);
15271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("\n");
15272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Failure of this assertion is serious and denotes a bug in
15274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         disInstr. */
15275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vpanic("disInstr_X86: inconsistency in LOCK prefix handling");
15276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
15279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
15280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
15283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                         guest_x86_toIR.c ---*/
15284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
15285