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
10436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Copyright (C) 2004-2013 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   * some of the FCOM cases could do with testing -- not convinced
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     that the args are the right way round.
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FSAVE does not re-initialise the FPU; it should do
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FINIT not only initialises the FPU environment, it also
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     zeroes all the FP registers.  It should leave the registers
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     unchanged.
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SAHF should cause eflags[1] == 1, and in fact it produces 0.  As
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   per Intel docs this bit has no meaning anyway.  Since PUSHF is the
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   only way to observe eflags[1], a proper fix would be to make that
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bit be set by PUSHF.
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The state of %eflags.AC (alignment check, bit 18) is recorded by
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the simulation (viz, if you set it with popf then a pushf produces
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the value you set it to), but it is otherwise ignored.  In
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   particular, setting it to 1 does NOT cause alignment checking to
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   happen.  Programs that set it to 1 and then rely on the resulting
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SIGBUSs to inform them of misaligned accesses will not work.
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Implementation of sysenter is necessarily partial.  sysenter is a
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   kind of system call entry.  When doing a sysenter, the return
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   address is not known -- that is something that is beyond Vex's
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   knowledge.  So the generated IR forces a return to the scheduler,
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which can do what it likes to simulate the systenter, but it MUST
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   set this thread's guest_EIP field with the continuation address
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   before resuming execution.  If that doesn't happen, the thread will
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   jump to address zero, which is probably fatal.
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This module uses global variables and so is not MT-safe (if that
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   should ever become relevant).
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The delta values are 32-bit ints, not 64-bit ints.  That means
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   this module may not work right if run on a 64-bit host.  That should
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   be fixed properly, really -- if anyone ever wants to use Vex to
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   translate x86 code for execution on a 64-bit host.
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   casLE (implementation of lock-prefixed insns) and rep-prefixed
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insns: the side-exit back to the start of the insn is done with
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ijk_Boring.  This is quite wrong, it should be done with
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ijk_NoRedir, since otherwise the side exit, which is intended to
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   restart the instruction for whatever reason, could go somewhere
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   entirely else.  Doing it right (with Ijk_NoRedir jumps) would make
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   no-redir jumps performance critical, at least for rep-prefixed
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instructions, since all iterations thereof would involve such a
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   jump.  It's not such a big deal with casLE since the side exit is
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   only taken if the CAS fails, that is, the location is contended,
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which is relatively unlikely.
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XXXX: Nov 2009: handling of SWP on ARM suffers from the same
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   problem.
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Note also, the test for CAS success vs failure is done using
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Iop_CasCmp{EQ,NE}{8,16,32,64} rather than the ordinary
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Iop_Cmp{EQ,NE} equivalents.  This is so as to tell Memcheck that it
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shouldn't definedness-check these comparisons.  See
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   COMMENT_ON_CasCmpEQ in memcheck/mc_translate.c for
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   background/rationale.
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Performance holes:
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - fcom ; fstsw %ax ; sahf
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     sahf does not update the O flag (sigh) and so O needs to
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     be computed.  This is done expensively; it would be better
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     to have a calculate_eflags_o helper.
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - emwarns; some FP codes can generate huge numbers of these
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if the fpucw is changed in an inner loop.  It would be
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     better for the guest state to have an emwarn-enable reg
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     which can be set zero or nonzero.  If it is zero, emwarns
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     are not flagged, and instead control just flows all the
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     way through bbs as usual.
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* "Special" instructions.
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This instruction decoder can decode three special instructions
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which mean nothing natively (are no-ops as far as regs/mem are
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   concerned) but have meaning for supporting Valgrind.  A special
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction is flagged by the 12-byte preamble C1C703 C1C70D C1C71D
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   C1C713 (in the standard interpretation, that means: roll $3, %edi;
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   roll $13, %edi; roll $29, %edi; roll $19, %edi).  Following that,
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   one of the following 3 are allowed (standard interpretation in
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   parentheses):
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      87DB (xchgl %ebx,%ebx)   %EDX = client_request ( %EAX )
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      87C9 (xchgl %ecx,%ecx)   %EAX = guest_NRADDR
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      87D2 (xchgl %edx,%edx)   call-noredir *%EAX
147436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      87FF (xchgl %edi,%edi)   IR injection
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Any other bytes following the 12-byte preamble are illegal and
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   constitute a failure in instruction decoding.  This all assumes
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that the preamble will never occur except in specific code
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fragments designed for Valgrind to catch.
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   No prefixes may precede a "Special" instruction.
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* LOCK prefixed instructions.  These are translated using IR-level
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CAS statements (IRCAS) and are believed to preserve atomicity, even
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from the point of view of some other process racing against a
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   simulated one (presumably they communicate via a shared memory
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   segment).
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Handlers which are aware of LOCK prefixes are:
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_op2_G_E      (add, or, adc, sbb, and, sub, xor)
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_cmpxchg_G_E  (cmpxchg)
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp1         (add, or, adc, sbb, and, sub, xor)
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp3         (not, neg)
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp4         (inc, dec)
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp5         (inc, dec)
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp8_Imm     (bts, btc, btr)
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_bt_G_E       (bts, btc, btr)
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_xadd_G_E     (xadd)
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_basictypes.h"
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_ir.h"
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex.h"
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_guest_x86.h"
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "main_util.h"
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "main_globals.h"
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "guest_generic_bb_to_IR.h"
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "guest_generic_x87.h"
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "guest_x86_defs.h"
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Globals                                              ---*/
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* These are set at the start of the translation of an insn, right
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   down in disInstr_X86, so that we don't have to pass them around
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   endlessly.  They are all constant during the translation of any
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   given insn. */
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* We need to know this to do sub-register accesses correctly. */
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool host_is_bigendian;
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Pointer to the guest code area (points to start of BB, not to the
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn being processed). */
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar* guest_code;
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The guest address corresponding to guest_code[0]. */
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr32 guest_EIP_bbstart;
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The guest address for the instruction currently being
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   translated. */
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr32 guest_EIP_curr_instr;
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The IRSB* into which we're generating code. */
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRSB* irsb;
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Debugging output                                     ---*/
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define DIP(format, args...)           \
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (vex_traceflags & VEX_TRACE_FE)  \
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_printf(format, ## args)
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define DIS(buf, format, args...)      \
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (vex_traceflags & VEX_TRACE_FE)  \
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_sprintf(buf, format, ## args)
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Offsets of various parts of the x86 guest state.     ---*/
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EAX       offsetof(VexGuestX86State,guest_EAX)
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EBX       offsetof(VexGuestX86State,guest_EBX)
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_ECX       offsetof(VexGuestX86State,guest_ECX)
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EDX       offsetof(VexGuestX86State,guest_EDX)
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_ESP       offsetof(VexGuestX86State,guest_ESP)
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EBP       offsetof(VexGuestX86State,guest_EBP)
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_ESI       offsetof(VexGuestX86State,guest_ESI)
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EDI       offsetof(VexGuestX86State,guest_EDI)
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EIP       offsetof(VexGuestX86State,guest_EIP)
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_OP     offsetof(VexGuestX86State,guest_CC_OP)
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_DEP1   offsetof(VexGuestX86State,guest_CC_DEP1)
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_DEP2   offsetof(VexGuestX86State,guest_CC_DEP2)
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_NDEP   offsetof(VexGuestX86State,guest_CC_NDEP)
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FPREGS    offsetof(VexGuestX86State,guest_FPREG[0])
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FPTAGS    offsetof(VexGuestX86State,guest_FPTAG[0])
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_DFLAG     offsetof(VexGuestX86State,guest_DFLAG)
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_IDFLAG    offsetof(VexGuestX86State,guest_IDFLAG)
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_ACFLAG    offsetof(VexGuestX86State,guest_ACFLAG)
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FTOP      offsetof(VexGuestX86State,guest_FTOP)
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FC3210    offsetof(VexGuestX86State,guest_FC3210)
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FPROUND   offsetof(VexGuestX86State,guest_FPROUND)
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CS        offsetof(VexGuestX86State,guest_CS)
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_DS        offsetof(VexGuestX86State,guest_DS)
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_ES        offsetof(VexGuestX86State,guest_ES)
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FS        offsetof(VexGuestX86State,guest_FS)
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_GS        offsetof(VexGuestX86State,guest_GS)
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_SS        offsetof(VexGuestX86State,guest_SS)
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_LDT       offsetof(VexGuestX86State,guest_LDT)
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_GDT       offsetof(VexGuestX86State,guest_GDT)
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_SSEROUND  offsetof(VexGuestX86State,guest_SSEROUND)
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM0      offsetof(VexGuestX86State,guest_XMM0)
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM1      offsetof(VexGuestX86State,guest_XMM1)
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM2      offsetof(VexGuestX86State,guest_XMM2)
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM3      offsetof(VexGuestX86State,guest_XMM3)
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM4      offsetof(VexGuestX86State,guest_XMM4)
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM5      offsetof(VexGuestX86State,guest_XMM5)
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM6      offsetof(VexGuestX86State,guest_XMM6)
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM7      offsetof(VexGuestX86State,guest_XMM7)
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
276436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define OFFB_EMNOTE    offsetof(VexGuestX86State,guest_EMNOTE)
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
278eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov#define OFFB_CMSTART   offsetof(VexGuestX86State,guest_CMSTART)
279eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov#define OFFB_CMLEN     offsetof(VexGuestX86State,guest_CMLEN)
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_NRADDR    offsetof(VexGuestX86State,guest_NRADDR)
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_IP_AT_SYSCALL offsetof(VexGuestX86State,guest_IP_AT_SYSCALL)
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helper bits and pieces for deconstructing the        ---*/
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- x86 insn stream.                                     ---*/
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is the Intel register encoding -- integer regs. */
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_EAX 0
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_ECX 1
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_EDX 2
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_EBX 3
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_ESP 4
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_EBP 5
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_ESI 6
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_EDI 7
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_AL (0+R_EAX)
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_AH (4+R_EAX)
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is the Intel register encoding -- segment regs. */
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_ES 0
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_CS 1
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_SS 2
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_DS 3
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_FS 4
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_GS 5
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add a statement to the list held by "irbb". */
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void stmt ( IRStmt* st )
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( irsb, st );
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate a new temporary of the given type. */
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp newTemp ( IRType ty )
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(isPlausibleIRType(ty));
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return newIRTemp( irsb->tyenv, ty );
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Various simple conversions */
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt extend_s_8to32( UInt x )
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (UInt)((((Int)x) << 24) >> 24);
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt extend_s_16to32 ( UInt x )
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (UInt)((((Int)x) << 16) >> 16);
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Fetch a byte from the guest insn stream. */
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar getIByte ( Int delta )
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return guest_code[delta];
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Extract the reg field from a modRM byte. */
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int gregOfRM ( UChar mod_reg_rm )
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (Int)( (mod_reg_rm >> 3) & 7 );
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Figure out whether the mod and rm parts of a modRM byte refer to a
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register or memory.  If so, the byte will have the form 11XXXYYY,
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   where YYY is the register number. */
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool epartIsReg ( UChar mod_reg_rm )
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool(0xC0 == (mod_reg_rm & 0xC0));
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ... and extract the register number ... */
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int eregOfRM ( UChar mod_reg_rm )
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (Int)(mod_reg_rm & 0x7);
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get a 8/16/32-bit unsigned value out of the insn stream. */
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar getUChar ( Int delta )
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar v = guest_code[delta+0];
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toUChar(v);
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt getUDisp16 ( Int delta )
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt v = guest_code[delta+1]; v <<= 8;
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+0];
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return v & 0xFFFF;
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt getUDisp32 ( Int delta )
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt v = guest_code[delta+3]; v <<= 8;
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+2]; v <<= 8;
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+1]; v <<= 8;
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+0];
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return v;
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt getUDisp ( Int size, Int delta )
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (size) {
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return getUDisp32(delta);
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return getUDisp16(delta);
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return (UInt)getUChar(delta);
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("getUDisp(x86)");
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0; /*notreached*/
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get a byte value out of the insn stream and sign-extend to 32
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bits. */
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt getSDisp8 ( Int delta )
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return extend_s_8to32( (UInt) (guest_code[delta]) );
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt getSDisp16 ( Int delta0 )
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar* eip = (UChar*)(&guest_code[delta0]);
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt d = *eip++;
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   d |= ((*eip++) << 8);
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return extend_s_16to32(d);
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt getSDisp ( Int size, Int delta )
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (size) {
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return getUDisp32(delta);
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return getSDisp16(delta);
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return getSDisp8(delta);
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("getSDisp(x86)");
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return 0; /*notreached*/
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helpers for constructing IR.                         ---*/
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Create a 1/2/4 byte read of an x86 integer registers.  For 16/8 bit
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register references, we need to take the host endianness into
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   account.  Supplied value is 0 .. 7 and in the Intel instruction
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   encoding. */
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRType szToITy ( Int n )
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (n) {
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return Ity_I8;
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return Ity_I16;
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return Ity_I32;
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("szToITy(x86)");
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* On a little-endian host, less significant bits of the guest
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   registers are at lower addresses.  Therefore, if a reference to a
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register low half has the safe guest state offset as a reference to
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the full register.
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int integerGuestRegOffset ( Int sz, UInt archreg )
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg < 8);
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Correct for little-endian host only. */
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 || sz == 2 || (sz == 1 && archreg < 4)) {
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (archreg) {
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_EAX: return OFFB_EAX;
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_EBX: return OFFB_EBX;
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_ECX: return OFFB_ECX;
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_EDX: return OFFB_EDX;
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_ESI: return OFFB_ESI;
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_EDI: return OFFB_EDI;
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_ESP: return OFFB_ESP;
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_EBP: return OFFB_EBP;
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vpanic("integerGuestRegOffset(x86,le)(4,2)");
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg >= 4 && archreg < 8 && sz == 1);
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (archreg-4) {
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_EAX: return 1+ OFFB_EAX;
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_EBX: return 1+ OFFB_EBX;
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_ECX: return 1+ OFFB_ECX;
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_EDX: return 1+ OFFB_EDX;
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("integerGuestRegOffset(x86,le)(1h)");
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* NOTREACHED */
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("integerGuestRegOffset(x86,le)");
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int segmentGuestRegOffset ( UInt sreg )
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sreg) {
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_ES: return OFFB_ES;
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_CS: return OFFB_CS;
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_SS: return OFFB_SS;
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_DS: return OFFB_DS;
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_FS: return OFFB_FS;
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_GS: return OFFB_GS;
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("segmentGuestRegOffset(x86)");
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int xmmGuestRegOffset ( UInt xmmreg )
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (xmmreg) {
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: return OFFB_XMM0;
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return OFFB_XMM1;
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return OFFB_XMM2;
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: return OFFB_XMM3;
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return OFFB_XMM4;
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5: return OFFB_XMM5;
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: return OFFB_XMM6;
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7: return OFFB_XMM7;
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("xmmGuestRegOffset");
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lanes of vector registers are always numbered from zero being the
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   least significant lane (rightmost in the register).  */
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Correct for little-endian host only. */
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(laneno >= 0 && laneno < 8);
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Correct for little-endian host only. */
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(laneno >= 0 && laneno < 4);
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Correct for little-endian host only. */
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(laneno >= 0 && laneno < 2);
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getIReg ( Int sz, UInt archreg )
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 1 || sz == 2 || sz == 4);
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg < 8);
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( integerGuestRegOffset(sz,archreg),
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      szToITy(sz) );
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Ditto, but write to a reg instead. */
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putIReg ( Int sz, UInt archreg, IRExpr* e )
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = typeOfIRExpr(irsb->tyenv, e);
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: vassert(ty == Ity_I8); break;
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: vassert(ty == Ity_I16); break;
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: vassert(ty == Ity_I32); break;
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("putIReg(x86)");
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg < 8);
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getSReg ( UInt sreg )
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putSReg ( UInt sreg, IRExpr* e )
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMReg ( UInt xmmreg )
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMReg ( UInt xmmreg, IRExpr* e )
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_V128);
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F64);
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F32);
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void assign ( IRTemp dst, IRExpr* e )
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_WrTmp(dst, e) );
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void storeLE ( IRExpr* addr, IRExpr* data )
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Store(Iend_LE, addr, data) );
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* unop ( IROp op, IRExpr* a )
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Unop(op, a);
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Binop(op, a1, a2);
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Triop(op, a1, a2, a3);
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkexpr ( IRTemp tmp )
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_RdTmp(tmp);
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU8 ( UInt i )
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(i < 256);
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U8( (UChar)i ));
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU16 ( UInt i )
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(i < 65536);
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U16( (UShort)i ));
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU32 ( UInt i )
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U32(i));
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU64 ( ULong i )
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U64(i));
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU ( IRType ty, UInt i )
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ty == Ity_I8)  return mkU8(i);
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ty == Ity_I16) return mkU16(i);
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ty == Ity_I32) return mkU32(i);
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If this panics, it usually means you passed a size (1,2,4)
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      value as the IRType, rather than a real IRType. */
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("mkU(x86)");
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkV128 ( UShort mask )
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_V128(mask));
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* loadLE ( IRType ty, IRExpr* addr )
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Load(Iend_LE, ty, addr);
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IROp mkSizedOp ( IRType ty, IROp op8 )
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int adj;
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_Mul8
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_CasCmpNE8
715436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           || op8 == Iop_ExpCmpNE8
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_Not8);
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return adj + op8;
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szSmall == 1 && szBig == 4) {
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return signd ? Iop_8Sto32 : Iop_8Uto32;
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szSmall == 1 && szBig == 2) {
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return signd ? Iop_8Sto16 : Iop_8Uto16;
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szSmall == 2 && szBig == 4) {
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return signd ? Iop_16Sto32 : Iop_16Uto32;
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("mkWidenOp(x86,guest)");
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkAnd1 ( IRExpr* x, IRExpr* y )
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,x) == Ity_I1);
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,y) == Ity_I1);
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return unop(Iop_32to1,
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_And32,
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto32,x),
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto32,y)));
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate a compare-and-swap operation, operating on memory at
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'addr'.  The expected value is 'expVal' and the new value is
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'newVal'.  If the operation fails, then transfer control (with a
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   no-redir jump (XXX no -- see comment at top of this file)) to
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'restart_point', which is presumably the address of the guest
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction again -- retrying, essentially. */
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void casLE ( IRExpr* addr, IRExpr* expVal, IRExpr* newVal,
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Addr32 restart_point )
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRCAS* cas;
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType tyE    = typeOfIRExpr(irsb->tyenv, expVal);
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType tyN    = typeOfIRExpr(irsb->tyenv, newVal);
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp oldTmp = newTemp(tyE);
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp expTmp = newTemp(tyE);
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(tyE == tyN);
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(tyE == Ity_I32 || tyE == Ity_I16 || tyE == Ity_I8);
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(expTmp, expVal);
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cas = mkIRCAS( IRTemp_INVALID, oldTmp, Iend_LE, addr,
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  NULL, mkexpr(expTmp), NULL, newVal );
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_CAS(cas) );
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Exit(
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( mkSizedOp(tyE,Iop_CasCmpNE8),
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mkexpr(oldTmp), mkexpr(expTmp) ),
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Ijk_Boring, /*Ijk_NoRedir*/
769663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            IRConst_U32( restart_point ),
770663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            OFFB_EIP
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helpers for %eflags.                                 ---*/
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Evaluating the flags-thunk. -------------- */
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate all the eflags from stored
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression ::
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ity_I32. */
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_x86g_calculate_eflags_all ( void )
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* call
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprCCall(
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Ity_I32,
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           0/*regparm*/,
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           "x86g_calculate_eflags_all", &x86g_calculate_eflags_all,
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           args
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Exclude OP and NDEP from definedness checking.  We're only
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      interested in DEP1 and DEP2. */
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return call;
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate some particular condition from stored
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression ::
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ity_Bit. */
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_x86g_calculate_condition ( X86Condcode cond )
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprVec_5( mkU32(cond),
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_OP,  Ity_I32),
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* call
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprCCall(
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Ity_I32,
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           0/*regparm*/,
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           "x86g_calculate_condition", &x86g_calculate_condition,
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           args
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Exclude the requested condition, OP and NDEP from definedness
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      checking.  We're only interested in DEP1 and DEP2. */
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return unop(Iop_32to1, call);
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate just the carry flag from stored
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression :: Ity_I32. */
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_x86g_calculate_eflags_c ( void )
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* call
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprCCall(
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Ity_I32,
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           3/*regparm*/,
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           "x86g_calculate_eflags_c", &x86g_calculate_eflags_c,
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           args
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Exclude OP and NDEP from definedness checking.  We're only
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      interested in DEP1 and DEP2. */
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return call;
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Building the flags-thunk. -------------- */
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The machinery in this section builds the flag-thunk following a
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   flag-setting operation.  Hence the various setFlags_* functions.
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool isAddSub ( IROp op8 )
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool isLogic ( IROp op8 )
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* U-widen 8/16/32 bit int expr to 32. */
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* widenUto32 ( IRExpr* e )
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (typeOfIRExpr(irsb->tyenv,e)) {
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: return e;
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: return unop(Iop_16Uto32,e);
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:  return unop(Iop_8Uto32,e);
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("widenUto32");
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* S-widen 8/16/32 bit int expr to 32. */
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* widenSto32 ( IRExpr* e )
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (typeOfIRExpr(irsb->tyenv,e)) {
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: return e;
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: return unop(Iop_16Sto32,e);
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:  return unop(Iop_8Sto32,e);
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("widenSto32");
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Narrow 8/16/32 bit int expr to 8/16/32.  Clearly only some
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of these combinations make sense. */
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType src_ty = typeOfIRExpr(irsb->tyenv,e);
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (src_ty == dst_ty)
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return e;
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (src_ty == Ity_I32 && dst_ty == Ity_I16)
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_32to16, e);
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (src_ty == Ity_I32 && dst_ty == Ity_I8)
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_32to8, e);
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf("\nsrc, dst tys are: ");
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ppIRType(src_ty);
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf(", ");
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ppIRType(dst_ty);
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf("\n");
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("narrowTo(x86)");
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Set the flags thunk OP, DEP1 and DEP2 fields.  The supplied op is
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   auto-sized up to the real op. */
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op8) {
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Add8: ccOp += X86G_CC_OP_ADDB;   break;
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Sub8: ccOp += X86G_CC_OP_SUBB;   break;
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:       ppIROp(op8);
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vpanic("setFlags_DEP1_DEP2(x86)");
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(ccOp)) );
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Set the OP and DEP1 fields only, and write zero to DEP2. */
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op8) {
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Or8:
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_And8:
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Xor8: ccOp += X86G_CC_OP_LOGICB; break;
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:       ppIROp(op8);
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vpanic("setFlags_DEP1(x86)");
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(ccOp)) );
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For shift operations, we put in the result and the undershifted
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   result.  Except if the shift amount is zero, the thunk is left
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unchanged. */
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void setFlags_DEP1_DEP2_shift ( IROp    op32,
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       IRTemp  res,
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       IRTemp  resUS,
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       IRType  ty,
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       IRTemp  guard )
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guard);
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Both kinds of right shifts are handled by the same thunk
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      operation. */
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op32) {
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shr32:
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Sar32: ccOp = X86G_CC_OP_SHRL - ccOp; break;
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shl32: ccOp = X86G_CC_OP_SHLL - ccOp; break;
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:        ppIROp(op32);
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      vpanic("setFlags_DEP1_DEP2_shift(x86)");
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
985436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* guard :: Ity_I8.  We need to convert it to I1. */
986436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   IRTemp guardB = newTemp(Ity_I1);
987436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   assign( guardB, binop(Iop_CmpNE8, mkexpr(guard), mkU8(0)) );
988436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* DEP1 contains the result, DEP2 contains the undershifted value. */
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,
991436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                     IRExpr_ITE( mkexpr(guardB),
992436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 mkU32(ccOp),
993436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 IRExpr_Get(OFFB_CC_OP,Ity_I32) ) ));
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1,
995436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                     IRExpr_ITE( mkexpr(guardB),
996436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 widenUto32(mkexpr(res)),
997436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 IRExpr_Get(OFFB_CC_DEP1,Ity_I32) ) ));
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2,
999436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                     IRExpr_ITE( mkexpr(guardB),
1000436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 widenUto32(mkexpr(resUS)),
1001436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 IRExpr_Get(OFFB_CC_DEP2,Ity_I32) ) ));
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
1004b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   stmt( IRStmt_Put( OFFB_CC_NDEP,
1005436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                     IRExpr_ITE( mkexpr(guardB),
1006436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 mkU32(0),
1007436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 IRExpr_Get(OFFB_CC_NDEP,Ity_I32) ) ));
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For the inc/dec case, we store in DEP1 the result value and in NDEP
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the former value of the carry flag, which unfortunately we have to
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   compute. */
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int ccOp = inc ? X86G_CC_OP_INCB : X86G_CC_OP_DECB;
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This has to come first, because calculating the C flag
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      may require reading all four thunk fields. */
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mk_x86g_calculate_eflags_c()) );
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(ccOp)) );
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(res))) );
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   two arguments. */
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (ty) {
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16:
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32:
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("setFlags_MUL(x86)");
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Condition codes. -------------- */
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Condition codes, using the Intel encoding.  */
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1062436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic const HChar* name_X86Condcode ( X86Condcode cond )
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (cond) {
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondO:      return "o";
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNO:     return "no";
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondB:      return "b";
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNB:     return "nb";
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondZ:      return "z";
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNZ:     return "nz";
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondBE:     return "be";
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNBE:    return "nbe";
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondS:      return "s";
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNS:     return "ns";
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondP:      return "p";
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNP:     return "np";
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondL:      return "l";
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNL:     return "nl";
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondLE:     return "le";
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondNLE:    return "nle";
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case X86CondAlways: return "ALWAYS";
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("name_X86Condcode");
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownX86Condcode positiveIse_X86Condcode ( X86Condcode  cond,
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      Bool*        needInvert )
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(cond >= X86CondO && cond <= X86CondNLE);
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cond & 1) {
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *needInvert = True;
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return cond-1;
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *needInvert = False;
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return cond;
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Helpers for ADD/SUB with carry. -------------- */
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   appropriately.
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Optionally, generate a store for the 'tres' value.  This can either
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   be a normal store, or it can be a cas-with-possible-failure style
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   store:
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if taddr is IRTemp_INVALID, then no store is generated.
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if taddr is not IRTemp_INVALID, then a store (using taddr as
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the address) is generated:
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if texpVal is IRTemp_INVALID then a normal store is
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     generated, and restart_point must be zero (it is irrelevant).
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if texpVal is not IRTemp_INVALID then a cas-style store is
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     generated.  texpVal is the expected value, restart_point
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     is the restart point if the store fails, and texpVal must
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     have the same type as tres.
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void helper_ADC ( Int sz,
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp tres, IRTemp ta1, IRTemp ta2,
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /* info about optional store: */
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt    thunkOp;
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty    = szToITy(sz);
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldc  = newTemp(Ity_I32);
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldcn = newTemp(ty);
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    plus  = mkSizedOp(ty, Iop_Add8);
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    xor   = mkSizedOp(ty, Iop_Xor8);
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 1 || sz == 2 || sz == 4);
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thunkOp = sz==4 ? X86G_CC_OP_ADCL
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   : (sz==2 ? X86G_CC_OP_ADCW : X86G_CC_OP_ADCB);
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* oldc = old carry flag, 0 or 1 */
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldc,  binop(Iop_And32,
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mk_x86g_calculate_eflags_c(),
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32(1)) );
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tres, binop(plus,
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(plus,mkexpr(ta1),mkexpr(ta2)),
1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(oldcn)) );
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Possibly generate a store of 'tres' to 'taddr'.  See comment at
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      start of this function. */
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (taddr != IRTemp_INVALID) {
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (texpVal == IRTemp_INVALID) {
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(restart_point == 0);
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(taddr), mkexpr(tres) );
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* .. and hence 'texpVal' has the same type as 'tres'. */
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         casLE( mkexpr(taddr),
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mkexpr(texpVal), mkexpr(tres), restart_point );
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(thunkOp) ) );
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1)) ));
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                         mkexpr(oldcn)) )) );
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   appropriately.  As with helper_ADC, possibly generate a store of
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the result -- see comments on helper_ADC for details.
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void helper_SBB ( Int sz,
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp tres, IRTemp ta1, IRTemp ta2,
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /* info about optional store: */
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt    thunkOp;
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty    = szToITy(sz);
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldc  = newTemp(Ity_I32);
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldcn = newTemp(ty);
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    minus = mkSizedOp(ty, Iop_Sub8);
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    xor   = mkSizedOp(ty, Iop_Xor8);
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 1 || sz == 2 || sz == 4);
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thunkOp = sz==4 ? X86G_CC_OP_SBBL
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   : (sz==2 ? X86G_CC_OP_SBBW : X86G_CC_OP_SBBB);
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* oldc = old carry flag, 0 or 1 */
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldc, binop(Iop_And32,
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mk_x86g_calculate_eflags_c(),
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(1)) );
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tres, binop(minus,
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(minus,mkexpr(ta1),mkexpr(ta2)),
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(oldcn)) );
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Possibly generate a store of 'tres' to 'taddr'.  See comment at
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      start of this function. */
1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (taddr != IRTemp_INVALID) {
1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (texpVal == IRTemp_INVALID) {
1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(restart_point == 0);
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(taddr), mkexpr(tres) );
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* .. and hence 'texpVal' has the same type as 'tres'. */
1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         casLE( mkexpr(taddr),
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mkexpr(texpVal), mkexpr(tres), restart_point );
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(thunkOp) ) );
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1) )) );
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                         mkexpr(oldcn)) )) );
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Helpers for disassembly printing. -------------- */
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1229436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic const HChar* nameGrp1 ( Int opc_aux )
1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1231436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static const HChar* grp1_names[8]
1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp1_names[opc_aux];
1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1237436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic const HChar* nameGrp2 ( Int opc_aux )
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1239436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static const HChar* grp2_names[8]
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp2_names[opc_aux];
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1245436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic const HChar* nameGrp4 ( Int opc_aux )
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1247436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static const HChar* grp4_names[8]
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp4_names[opc_aux];
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1253436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic const HChar* nameGrp5 ( Int opc_aux )
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1255436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static const HChar* grp5_names[8]
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp5_names[opc_aux];
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1261436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic const HChar* nameGrp8 ( Int opc_aux )
1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1263436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static const HChar* grp8_names[8]
1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(x86)");
1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp8_names[opc_aux];
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1269436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic const HChar* nameIReg ( Int size, Int reg )
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1271436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static const HChar* ireg32_names[8]
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%eax", "%ecx", "%edx", "%ebx",
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%esp", "%ebp", "%esi", "%edi" };
1274436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static const HChar* ireg16_names[8]
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
1276436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static const HChar* ireg8_names[8]
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%al", "%cl", "%dl", "%bl",
1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (reg < 0 || reg > 7) goto bad;
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (size) {
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return ireg32_names[reg];
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return ireg16_names[reg];
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return ireg8_names[reg];
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  bad:
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("nameIReg(X86)");
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return NULL; /*notreached*/
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1290436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic const HChar* nameSReg ( UInt sreg )
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sreg) {
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_ES: return "%es";
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_CS: return "%cs";
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_SS: return "%ss";
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_DS: return "%ds";
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_FS: return "%fs";
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_GS: return "%gs";
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameSReg(x86)");
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1303436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic const HChar* nameMMXReg ( Int mmxreg )
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1305436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static const HChar* mmx_names[8]
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return mmx_names[mmxreg];
1309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1311436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic const HChar* nameXMMReg ( Int xmmreg )
1312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1313436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static const HChar* xmm_names[8]
1314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (xmmreg < 0 || xmmreg > 7) vpanic("name_of_xmm_reg");
1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xmm_names[xmmreg];
1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1320436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic const HChar* nameMMXGran ( Int gran )
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gran) {
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: return "b";
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return "w";
1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return "d";
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: return "q";
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameMMXGran(x86,guest)");
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar nameISize ( Int size )
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (size) {
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return 'l';
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return 'w';
1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return 'b';
1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameISize(x86)");
1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- JMP helpers                                          ---*/
1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1346663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengstatic void jmp_lit( /*MOD*/DisResult* dres,
1347663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     IRJumpKind kind, Addr32 d32 )
1348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1349663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->whatNext    == Dis_Continue);
1350663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->len         == 0);
1351663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->continueAt  == 0);
1352663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->jk_StopHere == Ijk_INVALID);
1353663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres->whatNext    = Dis_StopHere;
1354663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres->jk_StopHere = kind;
1355663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   stmt( IRStmt_Put( OFFB_EIP, mkU32(d32) ) );
1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1358663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengstatic void jmp_treg( /*MOD*/DisResult* dres,
1359663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                      IRJumpKind kind, IRTemp t )
1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1361663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->whatNext    == Dis_Continue);
1362663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->len         == 0);
1363663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->continueAt  == 0);
1364663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->jk_StopHere == Ijk_INVALID);
1365663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres->whatNext    = Dis_StopHere;
1366663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres->jk_StopHere = kind;
1367663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   stmt( IRStmt_Put( OFFB_EIP, mkexpr(t) ) );
1368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1371663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengvoid jcc_01( /*MOD*/DisResult* dres,
1372663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng             X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
1373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool        invert;
1375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   X86Condcode condPos;
1376663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->whatNext    == Dis_Continue);
1377663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->len         == 0);
1378663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->continueAt  == 0);
1379663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->jk_StopHere == Ijk_INVALID);
1380663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres->whatNext    = Dis_StopHere;
1381663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres->jk_StopHere = Ijk_Boring;
1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   condPos = positiveIse_X86Condcode ( cond, &invert );
1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (invert) {
1384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
1385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Ijk_Boring,
1386663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         IRConst_U32(d32_false),
1387663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         OFFB_EIP ) );
1388663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      stmt( IRStmt_Put( OFFB_EIP, mkU32(d32_true) ) );
1389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
1391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Ijk_Boring,
1392663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         IRConst_U32(d32_true),
1393663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         OFFB_EIP ) );
1394663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      stmt( IRStmt_Put( OFFB_EIP, mkU32(d32_false) ) );
1395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassembling addressing modes                       ---*/
1401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1404436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovconst HChar* sorbTxt ( UChar sorb )
1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sorb) {
1407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0:    return ""; /* no override */
1408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x3E: return "%ds";
1409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x26: return "%es:";
1410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x64: return "%fs:";
1411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x65: return "%gs:";
1412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("sorbTxt(x86,guest)");
1413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 'virtual' is an IRExpr* holding a virtual address.  Convert it to a
1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   linear address by adding any required segment override as indicated
1419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   by sorb. */
1420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    sreg;
1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType hWordTy;
1425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sorb == 0)
1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* the common case - no override */
1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return virtual;
1430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sorb) {
1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x3E: sreg = R_DS; break;
1433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x26: sreg = R_ES; break;
1434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x64: sreg = R_FS; break;
1435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x65: sreg = R_GS; break;
1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("handleSegOverride(x86,guest)");
1437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   seg_selector = newTemp(Ity_I32);
1442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ldt_ptr      = newTemp(hWordTy);
1443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gdt_ptr      = newTemp(hWordTy);
1444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r64          = newTemp(Ity_I64);
1445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
1449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*
1451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Call this to do the translation and limit checks:
1452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
1453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 UInt seg_selector, UInt virtual_addr )
1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
1456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      r64,
1457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mkIRExprCCall(
1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Ity_I64,
1459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         0/*regparms*/,
1460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "x86g_use_seg_selector",
1461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         &x86g_use_seg_selector,
1462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
1463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(seg_selector), virtual)
1464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If the high 32 of the result are non-zero, there was a
1468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      failure in address translation.  In which case, make a
1469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      quick exit.
1470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt(
1472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Exit(
1473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
1474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Ijk_MapFail,
1475663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         IRConst_U32( guest_EIP_curr_instr ),
1476663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         OFFB_EIP
1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* otherwise, here's the translated result. */
1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return unop(Iop_64to32, mkexpr(r64));
1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate IR to calculate an address indicated by a ModRM and
1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   following SIB bytes.  The expression, and the number of bytes in
1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the address mode, are returned.  Note that this fn should not be
1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   called if the R/M part of the address denotes a register instead of
1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memory.  If print_codegen is true, text of the addressing mode is
1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   placed in buf.
1491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The computed address is stored in a new tempreg, and the
1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   identity of the tempreg is returned.  */
1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmp = newTemp(Ity_I32);
1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tmp, addr32 );
1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return tmp;
1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRTemp disAMode ( Int* len, UChar sorb, Int delta, HChar* buf )
1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar mod_reg_rm = getIByte(delta);
1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta++;
1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf[0] = (UChar)0;
1509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jump table seems a bit excessive.
1512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm &= 0xC7;                      /* is now XX000YYY */
1514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm  = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            /* is now XX0XXYYY */
1516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm &= 0x1F;                      /* is now 000XXYYY */
1517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (mod_reg_rm) {
1518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         --> GET %reg, t
1521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x00: case 0x01: case 0x02: case 0x03:
1523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         { UChar rm = mod_reg_rm;
1525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *len = 1;
1527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           return disAMode_copy2tmp(
1528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  handleSegOverride(sorb, getIReg(4,rm)));
1529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* d8(%eax) ... d8(%edi), not including d8(%esp)
1532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         --> GET %reg, t ; ADDL d8, t
1533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x08: case 0x09: case 0x0A: case 0x0B:
1535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         { UChar rm = toUChar(mod_reg_rm & 7);
1537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           UInt  d  = getSDisp8(delta);
1538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIS(buf, "%s%d(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
1539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *len = 2;
1540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           return disAMode_copy2tmp(
1541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  handleSegOverride(sorb,
1542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
1543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* d32(%eax) ... d32(%edi), not including d32(%esp)
1546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         --> GET %reg, t ; ADDL d8, t
1547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x10: case 0x11: case 0x12: case 0x13:
1549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 14 */ case 0x15: case 0x16: case 0x17:
1550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         { UChar rm = toUChar(mod_reg_rm & 7);
1551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           UInt  d  = getUDisp32(delta);
1552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
1553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *len = 5;
1554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           return disAMode_copy2tmp(
1555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  handleSegOverride(sorb,
1556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
1557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* a register, %eax .. %edi.  This shouldn't happen. */
1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x18: case 0x19: case 0x1A: case 0x1B:
1561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("disAMode(x86): not an addr!");
1563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* a 32-bit literal address
1565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         --> MOV d32, tmp
1566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x05:
1568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         { UInt d = getUDisp32(delta);
1569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *len = 5;
1570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
1571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           return disAMode_copy2tmp(
1572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     handleSegOverride(sorb, mkU32(d)));
1573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x04: {
1576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* SIB, with no displacement.  Special cases:
1577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            -- %esp cannot act as an index value.
1578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               If index_r indicates %esp, zero is used for the index.
1579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            -- when mod is zero and base indicates EBP, base is instead
1580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               a 32-bit literal.
1581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            It's all madness, I tell you.  Extract %index, %base and
1582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            scale from the SIB byte.  The value denoted is then:
1583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               | %index == %ESP && %base == %EBP
1584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               = d32 following SIB byte
1585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               | %index == %ESP && %base != %EBP
1586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               = %base
1587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               | %index != %ESP && %base == %EBP
1588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               = d32 following SIB byte + (%index << scale)
1589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               | %index != %ESP && %base != %ESP
1590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               = %base + (%index << scale)
1591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            What happens to the souls of CPU architects who dream up such
1593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            horrendous schemes, do you suppose?
1594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
1595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar sib     = getIByte(delta);
1596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar scale   = toUChar((sib >> 6) & 3);
1597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar index_r = toUChar((sib >> 3) & 7);
1598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar base_r  = toUChar(sib & 7);
1599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
1600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r != R_ESP && base_r != R_EBP) {
1602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 2;
1605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return
1606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               disAMode_copy2tmp(
1607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               handleSegOverride(sorb,
1608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Add32,
1609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getIReg(4,base_r),
1610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl32, getIReg(4,index_r),
1611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(scale)))));
1612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r != R_ESP && base_r == R_EBP) {
1615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UInt d = getUDisp32(delta);
1616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameIReg(4,index_r), 1<<scale);
1618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 6;
1619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return
1620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               disAMode_copy2tmp(
1621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               handleSegOverride(sorb,
1622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Add32,
1623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
1624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32(d))));
1625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r == R_ESP && base_r != R_EBP) {
1628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
1629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 2;
1630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return disAMode_copy2tmp(
1631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   handleSegOverride(sorb, getIReg(4,base_r)));
1632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r == R_ESP && base_r == R_EBP) {
1635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UInt d = getUDisp32(delta);
1636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s0x%x(,,)", sorbTxt(sorb), d);
1637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 6;
1638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return disAMode_copy2tmp(
1639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   handleSegOverride(sorb, mkU32(d)));
1640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
1642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
1643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, with 8-bit displacement.  Special cases:
1646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         -- %esp cannot act as an index value.
1647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            If index_r indicates %esp, zero is used for the index.
1648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Denoted value is:
1649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            | %index == %ESP
1650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = d8 + %base
1651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            | %index != %ESP
1652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = d8 + %base + (%index << scale)
1653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x0C: {
1655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar sib     = getIByte(delta);
1656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar scale   = toUChar((sib >> 6) & 3);
1657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar index_r = toUChar((sib >> 3) & 7);
1658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar base_r  = toUChar(sib & 7);
1659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt  d       = getSDisp8(delta+1);
1660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r == R_ESP) {
1662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   (Int)d, nameIReg(4,base_r));
1664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 3;
1665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return disAMode_copy2tmp(
1666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   handleSegOverride(sorb,
1667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
1668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
1669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 3;
1672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return
1673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                disAMode_copy2tmp(
1674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                handleSegOverride(sorb,
1675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Add32,
1676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Add32,
1677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              getIReg(4,base_r),
1678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl32,
1679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    getIReg(4,index_r), mkU8(scale))),
1680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32(d))));
1681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /*NOTREACHED*/
1683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
1684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, with 32-bit displacement.  Special cases:
1687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         -- %esp cannot act as an index value.
1688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            If index_r indicates %esp, zero is used for the index.
1689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Denoted value is:
1690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            | %index == %ESP
1691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = d32 + %base
1692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            | %index != %ESP
1693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = d32 + %base + (%index << scale)
1694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x14: {
1696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar sib     = getIByte(delta);
1697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar scale   = toUChar((sib >> 6) & 3);
1698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar index_r = toUChar((sib >> 3) & 7);
1699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar base_r  = toUChar(sib & 7);
1700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt d        = getUDisp32(delta+1);
1701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r == R_ESP) {
1703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   (Int)d, nameIReg(4,base_r));
1705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 6;
1706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return disAMode_copy2tmp(
1707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   handleSegOverride(sorb,
1708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
1709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
1710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 6;
1713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return
1714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                disAMode_copy2tmp(
1715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                handleSegOverride(sorb,
1716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Add32,
1717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Add32,
1718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              getIReg(4,base_r),
1719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl32,
1720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    getIReg(4,index_r), mkU8(scale))),
1721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32(d))));
1722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /*NOTREACHED*/
1724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
1725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
1728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("disAMode(x86)");
1729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 0; /*notreached*/
1730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Figure out the number of (insn-stream) bytes constituting the amode
1735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   beginning at delta.  Is useful for getting hold of literals beyond
1736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the end of the amode before it has been disassembled.  */
1737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt lengthAMode ( Int delta )
1739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar mod_reg_rm = getIByte(delta); delta++;
1741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jump table seems a bit excessive.
1744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm &= 0xC7;               /* is now XX000YYY */
1746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm  = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     /* is now XX0XXYYY */
1748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm &= 0x1F;               /* is now 000XXYYY */
1749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (mod_reg_rm) {
1750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x00: case 0x01: case 0x02: case 0x03:
1753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 1;
1755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x08: case 0x09: case 0x0A: case 0x0B:
1758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 2;
1760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x10: case 0x11: case 0x12: case 0x13:
1763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 14 */ case 0x15: case 0x16: case 0x17:
1764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 5;
1765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* a register, %eax .. %edi.  (Not an addr, but still handled.) */
1767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x18: case 0x19: case 0x1A: case 0x1B:
1768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 1;
1770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* a 32-bit literal address. */
1772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x05: return 5;
1773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, no displacement.  */
1775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x04: {
1776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar sib    = getIByte(delta);
1777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar base_r = toUChar(sib & 7);
1778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (base_r == R_EBP) return 6; else return 2;
1779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, with 8-bit displacement.  */
1781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x0C: return 3;
1782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, with 32-bit displacement.  */
1784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x14: return 6;
1785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
1787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("lengthAMode");
1788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 0; /*notreached*/
1789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassembling common idioms                          ---*/
1794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle binary integer instructions of the form
1797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op E, G  meaning
1798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op reg-or-mem, reg
1799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Is passed the a ptr to the modRM byte, the actual operation, and the
1800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   data size.  Returns the address advanced completely over this
1801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction.
1802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(src) is reg-or-mem
1804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(dst) is reg.
1805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %G,  tmp
1807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP %E,   tmp
1808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmp, %G
1809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem and OP is not reversible,
1811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                -->    (getAddr E) -> tmpa
1812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmpa
1813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       GET %G, tmp2
1814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP tmpa, tmp2
1815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmp2, %G
1816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem and OP is reversible
1818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                -->    (getAddr E) -> tmpa
1819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmpa
1820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP %G, tmpa
1821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpa, %G
1822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_op2_E_G ( UChar       sorb,
1825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Bool        addSubCarry,
1826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   IROp        op8,
1827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Bool        keep,
1828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         size,
1829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         delta0,
1830436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                   const HChar* t_x86opc )
1831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
1833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
1834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty   = szToITy(size);
1835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst1 = newTemp(ty);
1836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  src  = newTemp(ty);
1837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst0 = newTemp(ty);
1838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getUChar(delta0);
1839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr = IRTemp_INVALID;
1840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* addSubCarry == True indicates the intended operation is
1842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add-with-carry or subtract-with-borrow. */
1843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (addSubCarry) {
1844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(keep);
1846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
1849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Specially handle XOR reg,reg, because that doesn't really
1850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         depend on reg, and doing the obvious thing potentially
1851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         generates a spurious value check failure due to the bogus
1852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dependency.  Ditto SBB reg,reg. */
1853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && gregOfRM(rm) == eregOfRM(rm)) {
1855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, gregOfRM(rm), mkU(ty,0));
1856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst0, getIReg(size,gregOfRM(rm)) );
1858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src,  getIReg(size,eregOfRM(rm)) );
1859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Add8) {
1861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_ADC( size, dst1, dst0, src,
1862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
1865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Sub8) {
1866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_SBB( size, dst1, dst0, src,
1867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
1871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
1872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
1873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
1874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
1875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (keep)
1876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(size, gregOfRM(rm), mkexpr(dst1));
1877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIReg(size,eregOfRM(rm)),
1881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIReg(size,gregOfRM(rm)));
1882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
1883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* E refers to memory */
1885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta0, dis_buf);
1886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst0, getIReg(size,gregOfRM(rm)) );
1887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src,  loadLE(szToITy(size), mkexpr(addr)) );
1888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Add8) {
1890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_ADC( size, dst1, dst0, src,
1891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
1894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Sub8) {
1895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_SBB( size, dst1, dst0, src,
1896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
1900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
1901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
1902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
1903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
1904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (keep)
1905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(size, gregOfRM(rm), mkexpr(dst1));
1906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          dis_buf,nameIReg(size,gregOfRM(rm)));
1910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
1911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle binary integer instructions of the form
1917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op G, E  meaning
1918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op reg, reg-or-mem
1919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Is passed the a ptr to the modRM byte, the actual operation, and the
1920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   data size.  Returns the address advanced completely over this
1921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction.
1922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(src) is reg.
1924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(dst) is reg-or-mem
1925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %E,  tmp
1927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP %G,   tmp
1928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmp, %E
1929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem, -->    (getAddr E) -> tmpa
1931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmpv
1932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP %G, tmpv
1933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       ST tmpv, (tmpa)
1934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_op2_G_E ( UChar       sorb,
1937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Bool        locked,
1938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Bool        addSubCarry,
1939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   IROp        op8,
1940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Bool        keep,
1941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         size,
1942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         delta0,
1943436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                   const HChar* t_x86opc )
1944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
1946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
1947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty   = szToITy(size);
1948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst1 = newTemp(ty);
1949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  src  = newTemp(ty);
1950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst0 = newTemp(ty);
1951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getIByte(delta0);
1952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr = IRTemp_INVALID;
1953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* addSubCarry == True indicates the intended operation is
1955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add-with-carry or subtract-with-borrow. */
1956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (addSubCarry) {
1957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(keep);
1959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
1962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Specially handle XOR reg,reg, because that doesn't really
1963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         depend on reg, and doing the obvious thing potentially
1964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         generates a spurious value check failure due to the bogus
1965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dependency.  Ditto SBB reg,reg.*/
1966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && gregOfRM(rm) == eregOfRM(rm)) {
1968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, eregOfRM(rm), mkU(ty,0));
1969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, getIReg(size,eregOfRM(rm)));
1971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src,  getIReg(size,gregOfRM(rm)));
1972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Add8) {
1974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_ADC( size, dst1, dst0, src,
1975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, eregOfRM(rm), mkexpr(dst1));
1977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
1978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Sub8) {
1979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_SBB( size, dst1, dst0, src,
1980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(size, eregOfRM(rm), mkexpr(dst1));
1982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
1984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
1985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
1986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
1987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
1988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (keep)
1989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(size, eregOfRM(rm), mkexpr(dst1));
1990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIReg(size,gregOfRM(rm)),
1994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIReg(size,eregOfRM(rm)));
1995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
1996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
1999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
2000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta0, dis_buf);
2001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, loadLE(ty,mkexpr(addr)));
2002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src,  getIReg(size,gregOfRM(rm)));
2003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Add8) {
2005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (locked) {
2006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* cas-style store */
2007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_ADC( size, dst1, dst0, src,
2008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* normal store */
2011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_ADC( size, dst1, dst0, src,
2012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, IRTemp_INVALID, 0 );
2013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
2015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Sub8) {
2016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (locked) {
2017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* cas-style store */
2018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_SBB( size, dst1, dst0, src,
2019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* normal store */
2022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_SBB( size, dst1, dst0, src,
2023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, IRTemp_INVALID, 0 );
2024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (keep) {
2028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
2029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0) vex_printf("locked case\n" );
2030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr),
2031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(dst0)/*expval*/,
2032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(dst1)/*newval*/, guest_EIP_curr_instr );
2033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
2034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0) vex_printf("nonlocked case\n");
2035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr), mkexpr(dst1));
2036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
2039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
2042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIReg(size,gregOfRM(rm)), dis_buf);
2046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
2047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle move instructions of the form
2052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mov E, G  meaning
2053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mov reg-or-mem, reg
2054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Is passed the a ptr to the modRM byte, and the data size.  Returns
2055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the address advanced completely over this instruction.
2056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(src) is reg-or-mem
2058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(dst) is reg.
2059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %E,  tmpv
2061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpv, %G
2062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem  -->    (getAddr E) -> tmpa
2064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmpb
2065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpb, %G
2066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_mov_E_G ( UChar       sorb,
2069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         size,
2070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         delta0 )
2071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int len;
2073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm = getIByte(delta0);
2074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
2075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
2077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
2078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s,%s\n", nameISize(size),
2079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg(size,eregOfRM(rm)),
2080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg(size,gregOfRM(rm)));
2081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
2082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
2085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
2086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
2087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
2088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s,%s\n", nameISize(size),
2089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           dis_buf,nameIReg(size,gregOfRM(rm)));
2090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta0+len;
2091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle move instructions of the form
2096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mov G, E  meaning
2097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mov reg, reg-or-mem
2098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Is passed the a ptr to the modRM byte, and the data size.  Returns
2099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the address advanced completely over this instruction.
2100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(src) is reg.
2102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(dst) is reg-or-mem
2103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %G,  tmp
2105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmp, %E
2106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem, -->    (getAddr E) -> tmpa
2108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       GET %G, tmpv
2109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       ST tmpv, (tmpa)
2110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_mov_G_E ( UChar       sorb,
2113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         size,
2114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         delta0 )
2115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int len;
2117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm = getIByte(delta0);
2118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
2119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
2121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
2122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s,%s\n", nameISize(size),
2123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg(size,gregOfRM(rm)),
2124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg(size,eregOfRM(rm)));
2125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
2126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
2129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
2130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
2131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
2132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s,%s\n", nameISize(size),
2133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg(size,gregOfRM(rm)), dis_buf);
2134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
2135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* op $immediate, AL/AX/EAX. */
2140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_op_imm_A ( Int    size,
2142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool   carrying,
2143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    IROp   op8,
2144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool   keep,
2145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int    delta,
2146436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    const HChar* t_x86opc )
2147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty   = szToITy(size);
2149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst0 = newTemp(ty);
2150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src  = newTemp(ty);
2151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst1 = newTemp(ty);
2152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt lit    = getUDisp(size,delta);
2153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(dst0, getIReg(size,R_EAX));
2154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(src,  mkU(ty,lit));
2155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isAddSub(op8) && !carrying) {
2157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2(op8, dst0, src, ty);
2159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isLogic(op8)) {
2162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!carrying);
2163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1(op8, dst1, ty);
2165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op8 == Iop_Add8 && carrying) {
2168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      helper_ADC( size, dst1, dst0, src,
2169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op8 == Iop_Sub8 && carrying) {
2173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      helper_SBB( size, dst1, dst0, src,
2174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vpanic("dis_op_imm_A(x86,guest)");
2178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (keep)
2180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, R_EAX, mkexpr(dst1));
2181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
2183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           lit, nameIReg(size,R_EAX));
2184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta+size;
2185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Sign- and Zero-extending moves. */
2189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_movx_E_G ( UChar      sorb,
2191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int delta, Int szs, Int szd, Bool sign_extend )
2192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm = getIByte(delta);
2194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
2195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (szd == szs) {
2196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // mutant case.  See #250799
2197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(szd, gregOfRM(rm),
2198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getIReg(szs,eregOfRM(rm)));
2199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // normal case
2201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(szd, gregOfRM(rm),
2202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      unop(mkWidenOp(szs,szd,sign_extend),
2203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getIReg(szs,eregOfRM(rm))));
2204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameISize(szs), nameISize(szd),
2207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(szs,eregOfRM(rm)),
2208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(szd,gregOfRM(rm)));
2209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta;
2210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
2213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
2214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    len;
2215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar  dis_buf[50];
2216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
2217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (szd == szs) {
2218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // mutant case.  See #250799
2219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(szd, gregOfRM(rm),
2220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           loadLE(szToITy(szs),mkexpr(addr)));
2221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // normal case
2223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(szd, gregOfRM(rm),
2224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      unop(mkWidenOp(szs,szd,sign_extend),
2225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           loadLE(szToITy(szs),mkexpr(addr))));
2226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameISize(szs), nameISize(szd),
2229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               dis_buf, nameIReg(szd,gregOfRM(rm)));
2230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta;
2231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
2236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   16 / 8 bit quantity in the given IRTemp.  */
2237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op    = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src64 = newTemp(Ity_I64);
2242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst64 = newTemp(Ity_I64);
2243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
2244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:
2245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src64, binop(Iop_32HLto64,
2246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              getIReg(4,R_EDX), getIReg(4,R_EAX)) );
2247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
2248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
2249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: {
2252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src64, unop(widen3264,
2255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_16HLto32,
2256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: {
2263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen816  = signed_divide ? Iop_8Sto16  : Iop_8Uto16;
2266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst64,
2268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, mkexpr(src64),
2269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(widen1632, unop(widen816, mkexpr(t)))) );
2270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(Iop_64to32,mkexpr(dst64)))) );
2272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(Iop_64HIto32,mkexpr(dst64)))) );
2274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("codegen_div(x86)");
2277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_Grp1 ( UChar sorb, Bool locked,
2283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Int delta, UChar modrm,
2284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Int am_sz, Int d_sz, Int sz, UInt d32 )
2285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
2287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
2288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty   = szToITy(sz);
2289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst1 = newTemp(ty);
2290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  src  = newTemp(ty);
2291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst0 = newTemp(ty);
2292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr = IRTemp_INVALID;
2293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    op8  = Iop_INVALID;
2294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt    mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
2295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregOfRM(modrm)) {
2297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: op8 = Iop_Add8; break;  case 1: op8 = Iop_Or8;  break;
2298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: break;  // ADC
2299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: break;  // SBB
2300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: op8 = Iop_And8; break;  case 5: op8 = Iop_Sub8; break;
2301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: op8 = Iop_Xor8; break;  case 7: op8 = Iop_Sub8; break;
2302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
2303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("dis_Grp1: unhandled case");
2304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
2307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(am_sz == 1);
2308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, getIReg(sz,eregOfRM(modrm)));
2310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src,  mkU(ty,d32 & mask));
2311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregOfRM(modrm) == 2 /* ADC */) {
2313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_ADC( sz, dst1, dst0, src,
2314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
2316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregOfRM(modrm) == 3 /* SBB */) {
2317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_SBB( sz, dst1, dst0, src,
2318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
2322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
2325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregOfRM(modrm) < 7)
2328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += (am_sz + d_sz);
2331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameIReg(sz,eregOfRM(modrm)));
2333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta, dis_buf);
2335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, loadLE(ty,mkexpr(addr)));
2337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src, mkU(ty,d32 & mask));
2338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregOfRM(modrm) == 2 /* ADC */) {
2340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (locked) {
2341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* cas-style store */
2342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_ADC( sz, dst1, dst0, src,
2343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* normal store */
2346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_ADC( sz, dst1, dst0, src,
2347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, IRTemp_INVALID, 0 );
2348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
2350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregOfRM(modrm) == 3 /* SBB */) {
2351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (locked) {
2352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* cas-style store */
2353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_SBB( sz, dst1, dst0, src,
2354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* normal store */
2357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_SBB( sz, dst1, dst0, src,
2358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, IRTemp_INVALID, 0 );
2359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregOfRM(modrm) < 7) {
2363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
2364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(dst0)/*expVal*/,
2365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkexpr(dst1)/*newVal*/,
2366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    guest_EIP_curr_instr );
2367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
2368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr), mkexpr(dst1));
2369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
2372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
2375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += (len+d_sz);
2378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              d32, dis_buf);
2380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
2382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 2 extended opcodes.  shift_expr must be an 8-bit typed
2386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   expression. */
2387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_Grp2 ( UChar sorb,
2390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Int delta, UChar modrm,
2391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
2392436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                const HChar* shift_expr_txt, Bool* decode_OK )
2393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* delta on entry points at the modrm byte. */
2395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
2396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    len;
2397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   isShift, isRotate, isRotateC;
2398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty    = szToITy(sz);
2399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst0  = newTemp(ty);
2400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst1  = newTemp(ty);
2401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp addr  = IRTemp_INVALID;
2402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True;
2404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 1 || sz == 2 || sz == 4);
2406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Put value to shift/rotate in dst0. */
2408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
2409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, getIReg(sz, eregOfRM(modrm)));
2410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += (am_sz + d_sz);
2411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta, dis_buf);
2413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, loadLE(ty,mkexpr(addr)));
2414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len + d_sz;
2415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   isShift = False;
2418b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   switch (gregOfRM(modrm)) { case 4: case 5: case 6: case 7: isShift = True; }
2419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   isRotate = False;
2421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   isRotateC = False;
2424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregOfRM(modrm)) { case 2: case 3: isRotateC = True; }
2425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!isShift && !isRotate && !isRotateC) {
2427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
2428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vpanic("dis_Grp2(Reg): unhandled case(x86)");
2429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isRotateC) {
2432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* call a helper; these insns are so ridiculous they do not
2433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         deserve better */
2434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool     left = toBool(gregOfRM(modrm) == 2);
2435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp   r64  = newTemp(Ity_I64);
2436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr** args
2437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          widenUto32(shift_expr),   /* rotate amount */
2439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          widenUto32(mk_x86g_calculate_eflags_all()),
2440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(sz) );
2441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( r64, mkIRExprCCall(
2442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64,
2443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      0/*regparm*/,
2444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      left ? "x86g_calculate_RCL" : "x86g_calculate_RCR",
2445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      left ? &x86g_calculate_RCL  : &x86g_calculate_RCR,
2446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      args
2447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )
2448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
2449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* new eflags in hi half r64; new value in lo half r64 */
2450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
2451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
2452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
2453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Set NDEP even though it isn't used.  This makes redundant-PUT
2455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         elimination of previous stores to this field work better. */
2456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
2457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isShift) {
2460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp pre32     = newTemp(Ity_I32);
2462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res32     = newTemp(Ity_I32);
2463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res32ss   = newTemp(Ity_I32);
2464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp shift_amt = newTemp(Ity_I8);
2465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   op32;
2466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
2468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: op32 = Iop_Shl32; break;
2469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 5: op32 = Iop_Shr32; break;
2470b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case 6: op32 = Iop_Shl32; break;
2471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 7: op32 = Iop_Sar32; break;
2472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
2473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vpanic("dis_Grp2:shift"); break;
2474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Widen the value to be shifted to 32 bits, do the shift, and
2477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         narrow back down.  This seems surprisingly long-winded, but
2478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unfortunately the Intel semantics requires that 8/16-bit
2479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         shifts give defined results for shift values all the way up
2480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to 31, and this seems the simplest way to do it.  It has the
2481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         advantage that the only IR level shifts generated are of 32
2482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bit values, and the shift amount is guaranteed to be in the
2483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         range 0 .. 31, thereby observing the IR semantics requiring
2484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         all shift values to be in the range 0 .. 2^word_size-1. */
2485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* shift_amt = shift_expr & 31, regardless of operation size */
2487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* suitably widen the value to be shifted to 32 bits. */
2490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     : widenUto32(mkexpr(dst0)) );
2492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* res32 = pre32 `shift` shift_amt */
2494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( res32ss,
2498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(op32,
2499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkexpr(pre32),
2500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And8,
2501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Sub8,
2502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(shift_amt), mkU8(1)),
2503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU8(31))) );
2504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Build the flags thunk. */
2506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
2507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Narrow the result back down. */
2509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst1, narrowTo(ty, mkexpr(res32)) );
2510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* if (isShift) */
2512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isRotate) {
2515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    ccOp      = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
2516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   left      = toBool(gregOfRM(modrm) == 0);
2517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rot_amt   = newTemp(Ity_I8);
2518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rot_amt32 = newTemp(Ity_I8);
2519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldFlags  = newTemp(Ity_I32);
2520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* rot_amt = shift_expr & mask */
2522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* By masking the rotate amount thusly, the IR-level Shl/Shr
2523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         expressions never shift beyond the word size and thus remain
2524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         well defined. */
2525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ty == Ity_I32)
2528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rot_amt, mkexpr(rot_amt32));
2529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
2530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
2531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (left) {
2533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1,
2536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( mkSizedOp(ty,Iop_Or8),
2537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( mkSizedOp(ty,Iop_Shl8),
2538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(dst0),
2539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(rot_amt)
2540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ),
2541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( mkSizedOp(ty,Iop_Shr8),
2542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(dst0),
2543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )
2545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
2546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
2547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ccOp += X86G_CC_OP_ROLB;
2548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else { /* right */
2550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1,
2553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( mkSizedOp(ty,Iop_Or8),
2554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( mkSizedOp(ty,Iop_Shr8),
2555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(dst0),
2556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(rot_amt)
2557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ),
2558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( mkSizedOp(ty,Iop_Shl8),
2559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(dst0),
2560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )
2562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
2563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
2564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ccOp += X86G_CC_OP_RORB;
2565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* dst1 now holds the rotated value.  Build flag thunk.  We
2569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         need the resulting value for this, and the previous flags.
2570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Except don't set it if the rotate count is zero. */
2571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(oldFlags, mk_x86g_calculate_eflags_all());
2573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2574436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* rot_amt32 :: Ity_I8.  We need to convert it to I1. */
2575436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      IRTemp rot_amt32b = newTemp(Ity_I1);
2576436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign(rot_amt32b, binop(Iop_CmpNE8, mkexpr(rot_amt32), mkU8(0)) );
2577436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
2578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* CC_DEP1 is the rotated value.  CC_NDEP is flags before. */
2579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,
2580436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        IRExpr_ITE( mkexpr(rot_amt32b),
2581436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    mkU32(ccOp),
2582436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    IRExpr_Get(OFFB_CC_OP,Ity_I32) ) ));
2583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1,
2584436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        IRExpr_ITE( mkexpr(rot_amt32b),
2585436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    widenUto32(mkexpr(dst1)),
2586436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    IRExpr_Get(OFFB_CC_DEP1,Ity_I32) ) ));
2587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2,
2588436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        IRExpr_ITE( mkexpr(rot_amt32b),
2589436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    mkU32(0),
2590436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    IRExpr_Get(OFFB_CC_DEP2,Ity_I32) ) ));
2591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP,
2592436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        IRExpr_ITE( mkexpr(rot_amt32b),
2593436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    mkexpr(oldFlags),
2594436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    IRExpr_Get(OFFB_CC_NDEP,Ity_I32) ) ));
2595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* if (isRotate) */
2596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Save result, and finish up. */
2598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
2599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (vex_traceflags & VEX_TRACE_FE) {
2601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("%s%c ",
2602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    nameGrp2(gregOfRM(modrm)), nameISize(sz) );
2603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (shift_expr_txt)
2604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vex_printf("%s", shift_expr_txt);
2605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ppIRExpr(shift_expr);
2607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE(mkexpr(addr), mkexpr(dst1));
2611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (vex_traceflags & VEX_TRACE_FE) {
2612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("%s%c ",
2613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    nameGrp2(gregOfRM(modrm)), nameISize(sz) );
2614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (shift_expr_txt)
2615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vex_printf("%s", shift_expr_txt);
2616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ppIRExpr(shift_expr);
2618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf(", %s\n", dis_buf);
2619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
2622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_Grp8_Imm ( UChar sorb,
2628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool locked,
2629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int delta, UChar modrm,
2630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int am_sz, Int sz, UInt src_val,
2631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool* decode_OK )
2632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* src_val denotes a d8.
2634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      And delta on entry points at the modrm byte. */
2635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty     = szToITy(sz);
2637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2     = newTemp(Ity_I32);
2638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2m    = newTemp(Ity_I32);
2639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t_addr = IRTemp_INVALID;
2640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
2641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   mask;
2642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* we're optimists :-) */
2644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True;
2645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Limit src_val -- the bit offset -- to something within a word.
2647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      The Intel docs say that literal offsets larger than a word are
2648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      masked in this way. */
2649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
2650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:  src_val &= 15; break;
2651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:  src_val &= 31; break;
2652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: *decode_OK = False; return delta;
2653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Invent a mask suitable for the operation. */
2656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregOfRM(modrm)) {
2657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: /* BT */  mask = 0;               break;
2658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5: /* BTS */ mask = 1 << src_val;    break;
2659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: /* BTR */ mask = ~(1 << src_val); break;
2660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7: /* BTC */ mask = 1 << src_val;    break;
2661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If this needs to be extended, probably simplest to make a
2662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            new function to handle the other cases (0 .. 3).  The
2663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Intel docs do however not indicate any use for 0 .. 3, so
2664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            we don't expect this to happen. */
2665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: *decode_OK = False; return delta;
2666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Fetch the value to be tested and modified into t2, which is
2669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      32-bits wide regardless of sz. */
2670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
2671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(am_sz == 1);
2672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t2, widenUto32(getIReg(sz, eregOfRM(modrm))) );
2673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += (am_sz + 1);
2674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              src_val, nameIReg(sz,eregOfRM(modrm)));
2676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int len;
2678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_addr = disAMode ( &len, sorb, delta, dis_buf);
2679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta  += (len+1);
2680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t2, widenUto32(loadLE(ty, mkexpr(t_addr))) );
2681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              src_val, dis_buf);
2683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Compute the new value into t2m, if non-BT. */
2686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregOfRM(modrm)) {
2687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: /* BT */
2688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5: /* BTS */
2690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2m, binop(Iop_Or32, mkU32(mask), mkexpr(t2)) );
2691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: /* BTR */
2693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2m, binop(Iop_And32, mkU32(mask), mkexpr(t2)) );
2694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7: /* BTC */
2696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2m, binop(Iop_Xor32, mkU32(mask), mkexpr(t2)) );
2697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
2699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/ /*the previous switch guards this*/
2700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
2701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Write the result back, if non-BT.  If the CAS fails then we
2704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      side-exit from the trace at this point, and so the flag state is
2705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      not affected.  This is of course as required. */
2706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (gregOfRM(modrm) != 4 /* BT */) {
2707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
2708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(sz, eregOfRM(modrm), narrowTo(ty, mkexpr(t2m)));
2709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (locked) {
2711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            casLE( mkexpr(t_addr),
2712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   narrowTo(ty, mkexpr(t2))/*expd*/,
2713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   narrowTo(ty, mkexpr(t2m))/*new*/,
2714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   guest_EIP_curr_instr );
2715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
2717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Copy relevant bit from t2 into the carry flag. */
2722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
2723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
2724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
2726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_CC_DEP1,
2727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And32,
2728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Shr32, mkexpr(t2), mkU8(src_val)),
2729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU32(1))
2730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ));
2731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
2732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
2733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
2734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
2736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Signed/unsigned widening multiply.  Generate IR to multiply the
2740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   value in EAX/AX/AL by the given IRTemp, and park the result in
2741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   EDX:EAX/DX:AX/AX.
2742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void codegen_mulL_A_D ( Int sz, Bool syned,
2744436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                               IRTemp tmp, const HChar* tmp_txt )
2745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
2747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1 = newTemp(ty);
2748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t1, getIReg(sz, R_EAX) );
2750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (ty) {
2752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: {
2753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res64   = newTemp(Ity_I64);
2754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resHi   = newTemp(Ity_I32);
2755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resLo   = newTemp(Ity_I32);
2756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   mulOp   = syned ? Iop_MullS32 : Iop_MullU32;
2757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
2758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
2759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resLo, unop(Iop_64to32,mkexpr(res64)));
2762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EDX, mkexpr(resHi));
2763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EAX, mkexpr(resLo));
2764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: {
2767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res32   = newTemp(Ity_I32);
2768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resHi   = newTemp(Ity_I16);
2769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resLo   = newTemp(Ity_I16);
2770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   mulOp   = syned ? Iop_MullS16 : Iop_MullU16;
2771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
2772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
2773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resLo, unop(Iop_32to16,mkexpr(res32)));
2776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(2, R_EDX, mkexpr(resHi));
2777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(2, R_EAX, mkexpr(resLo));
2778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8: {
2781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res16   = newTemp(Ity_I16);
2782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resHi   = newTemp(Ity_I8);
2783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resLo   = newTemp(Ity_I8);
2784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   mulOp   = syned ? Iop_MullS8 : Iop_MullU8;
2785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
2786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
2787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resLo, unop(Iop_16to8,mkexpr(res16)));
2790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(2, R_EAX, mkexpr(res16));
2791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
2794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("codegen_mulL_A_D(x86)");
2795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
2797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 3 extended opcodes. */
2801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_Grp3 ( UChar sorb, Bool locked, Int sz, Int delta, Bool* decode_OK )
2803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt    d32;
2805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   modrm;
2806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
2807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
2808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
2809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty = szToITy(sz);
2810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  t1 = newTemp(ty);
2811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst1, src, dst0;
2812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True; /* may change this later */
2814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm = getIByte(delta);
2816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (locked && (gregOfRM(modrm) != 2 && gregOfRM(modrm) != 3)) {
2818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LOCK prefix only allowed with not and neg subopcodes */
2819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decode_OK = False;
2820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta;
2821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
2824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
2825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: { /* TEST */
2826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++; d32 = getUDisp(sz, delta); delta += sz;
2827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
2828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               getIReg(sz,eregOfRM(modrm)),
2830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU(ty,d32)));
2831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1( Iop_And8, dst1, ty );
2832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      nameIReg(sz, eregOfRM(modrm)));
2834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* UNDEFINED */
2837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           /* The Intel docs imply this insn is undefined and binutils
2838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              agrees.  Unfortunately Core 2 will run it (with who
2839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              knows what result?)  sandpile.org reckons it's an alias
2840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              for case 0.  We play safe. */
2841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *decode_OK = False;
2842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
2843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: /* NOT */
2844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
2845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(sz, eregOfRM(modrm),
2846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(mkSizedOp(ty,Iop_Not8),
2847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             getIReg(sz, eregOfRM(modrm))));
2848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: /* NEG */
2851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
2852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst0 = newTemp(ty);
2853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            src  = newTemp(ty);
2854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
2855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst0, mkU(ty,0));
2856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(src,  getIReg(sz,eregOfRM(modrm)));
2857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
2858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
2859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: /* MUL (unsigned widening) */
2863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
2864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            src = newTemp(ty);
2865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(src, getIReg(sz,eregOfRM(modrm)));
2866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
2867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 5: /* IMUL (signed widening) */
2869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
2870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            src = newTemp(ty);
2871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(src, getIReg(sz,eregOfRM(modrm)));
2872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
2873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 6: /* DIV */
2875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
2876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, getIReg(sz, eregOfRM(modrm)) );
2877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_div ( sz, t1, False );
2878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 7: /* IDIV */
2881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
2882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, getIReg(sz, eregOfRM(modrm)) );
2883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_div ( sz, t1, True );
2884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
2887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* This can't happen - gregOfRM should return 0 .. 7 only */
2888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("Grp3(x86)");
2889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta, dis_buf );
2892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1   = newTemp(ty);
2893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
2894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, loadLE(ty,mkexpr(addr)));
2895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
2896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: { /* TEST */
2897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            d32 = getUDisp(sz, delta); delta += sz;
2898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
2899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(t1), mkU(ty,d32)));
2901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1( Iop_And8, dst1, ty );
2902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* UNDEFINED */
2906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           /* See comment above on R case */
2907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *decode_OK = False;
2908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
2909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: /* NOT */
2910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
2911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
2913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    guest_EIP_curr_instr );
2915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
2916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), mkexpr(dst1) );
2917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("not%c %s\n", nameISize(sz), dis_buf);
2919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: /* NEG */
2921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst0 = newTemp(ty);
2922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            src  = newTemp(ty);
2923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
2924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst0, mkU(ty,0));
2925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(src,  mkexpr(t1));
2926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, binop(mkSizedOp(ty,Iop_Sub8),
2927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(dst0), mkexpr(src)));
2928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
2929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    guest_EIP_curr_instr );
2931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
2932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), mkexpr(dst1) );
2933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
2935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("neg%c %s\n", nameISize(sz), dis_buf);
2936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: /* MUL */
2938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_mulL_A_D ( sz, False, t1, dis_buf );
2939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 5: /* IMUL */
2941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_mulL_A_D ( sz, True, t1, dis_buf );
2942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 6: /* DIV */
2944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_div ( sz, t1, False );
2945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("div%c %s\n", nameISize(sz), dis_buf);
2946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 7: /* IDIV */
2948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_div ( sz, t1, True );
2949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
2952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* This can't happen - gregOfRM should return 0 .. 7 only */
2953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("Grp3(x86)");
2954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
2957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 4 extended opcodes. */
2961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_Grp4 ( UChar sorb, Bool locked, Int delta, Bool* decode_OK )
2963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   alen;
2965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar modrm;
2966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
2967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = Ity_I8;
2968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1 = newTemp(ty);
2969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2 = newTemp(ty);
2970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True;
2972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm = getIByte(delta);
2974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
2976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LOCK prefix only allowed with inc and dec subopcodes */
2977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decode_OK = False;
2978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta;
2979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
2982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIReg(1, eregOfRM(modrm)));
2983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
2984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: /* INC */
2985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(1, eregOfRM(modrm), mkexpr(t2));
2987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( True, t2, ty );
2988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* DEC */
2990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(1, eregOfRM(modrm), mkexpr(t2));
2992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( False, t2, ty );
2993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
2994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
2995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
2996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
2997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
2999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
3000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameIReg(1, eregOfRM(modrm)));
3001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
3003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, loadLE(ty, mkexpr(addr)) );
3004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
3005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: /* INC */
3006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
3008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_EIP_curr_instr );
3010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), mkexpr(t2) );
3012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( True, t2, ty );
3014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* DEC */
3016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
3018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_EIP_curr_instr );
3020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), mkexpr(t2) );
3022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( False, t2, ty );
3024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
3026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
3027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
3028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
3030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
3031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
3033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 5 extended opcodes. */
3037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_Grp5 ( UChar sorb, Bool locked, Int sz, Int delta,
3039663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                /*MOD*/DisResult* dres, /*OUT*/Bool* decode_OK )
3040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
3042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   modrm;
3043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
3044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr = IRTemp_INVALID;
3045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty = szToITy(sz);
3046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  t1 = newTemp(ty);
3047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  t2 = IRTemp_INVALID;
3048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True;
3050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm = getIByte(delta);
3052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
3054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LOCK prefix only allowed with inc and dec subopcodes */
3055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decode_OK = False;
3056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta;
3057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
3060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIReg(sz,eregOfRM(modrm)));
3061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
3062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: /* INC */
3063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 2 || sz == 4);
3064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(ty);
3065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t1), mkU(ty,1)));
3067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( True, t2, ty );
3068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(sz,eregOfRM(modrm),mkexpr(t2));
3069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* DEC */
3071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 2 || sz == 4);
3072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(ty);
3073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t1), mkU(ty,1)));
3075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( False, t2, ty );
3076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(sz,eregOfRM(modrm),mkexpr(t2));
3077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: /* call Ev */
3079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 4);
3080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I32);
3081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(4, R_ESP, mkexpr(t2));
3083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+1));
3084663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_treg(dres, Ijk_Call, t1);
3085663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres->whatNext == Dis_StopHere);
3086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: /* jmp Ev */
3088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 4);
3089663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_treg(dres, Ijk_Boring, t1);
3090663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres->whatNext == Dis_StopHere);
3091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 6: /* PUSH Ev */
3093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 4 || sz == 2);
3094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I32);
3095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(4, R_ESP, mkexpr(t2) );
3097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(t2), mkexpr(t1) );
3098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
3100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
3101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
3102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
3104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
3106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta, dis_buf );
3108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, loadLE(ty,mkexpr(addr)));
3109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregOfRM(modrm)) {
3110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: /* INC */
3111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(ty);
3112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t1), mkU(ty,1)));
3114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
3115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr),
3116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr),mkexpr(t2));
3119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( True, t2, ty );
3121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* DEC */
3123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(ty);
3124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t1), mkU(ty,1)));
3126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (locked) {
3127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr),
3128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr),mkexpr(t2));
3131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( False, t2, ty );
3133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: /* call Ev */
3135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 4);
3136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I32);
3137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(4, R_ESP, mkexpr(t2));
3139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+len));
3140663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_treg(dres, Ijk_Call, t1);
3141663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres->whatNext == Dis_StopHere);
3142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: /* JMP Ev */
3144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 4);
3145663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_treg(dres, Ijk_Boring, t1);
3146663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres->whatNext == Dis_StopHere);
3147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 6: /* PUSH Ev */
3149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(sz == 4 || sz == 2);
3150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I32);
3151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(4, R_ESP, mkexpr(t2) );
3153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(t2), mkexpr(t1) );
3154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
3156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
3157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
3158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
3160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       nameISize(sz), dis_buf);
3162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
3164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassembling string ops (including REP prefixes)    ---*/
3169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Code shared by all the string ops */
3172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_string_op_increment(Int sz, Int t_inc)
3174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 || sz == 2) {
3176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_inc,
3177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
3178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(sz/2) ) );
3179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_inc,
3181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
3182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_string_op( void (*dis_OP)( Int, IRTemp ),
3187436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    Int sz, const HChar* name, UChar sorb )
3188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t_inc = newTemp(Ity_I32);
3190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sorb == 0); /* hmm.  so what was the point of passing it in? */
3191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dis_string_op_increment(sz, t_inc);
3192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dis_OP( sz, t_inc );
3193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%c\n", name, nameISize(sz));
3194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_MOVS ( Int sz, IRTemp t_inc )
3198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
3200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp td = newTemp(Ity_I32);   /* EDI */
3201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ts = newTemp(Ity_I32);   /* ESI */
3202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( td, getIReg(4, R_EDI) );
3204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ts, getIReg(4, R_ESI) );
3205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_LODS ( Int sz, IRTemp t_inc )
3214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
3216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ts = newTemp(Ity_I32);   /* ESI */
3217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ts, getIReg(4, R_ESI) );
3219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( sz, R_EAX, loadLE(ty, mkexpr(ts)) );
3221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_STOS ( Int sz, IRTemp t_inc )
3227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
3229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ta = newTemp(ty);        /* EAX */
3230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp td = newTemp(Ity_I32);   /* EDI */
3231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ta, getIReg(sz, R_EAX) );
3233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( td, getIReg(4, R_EDI) );
3234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   storeLE( mkexpr(td), mkexpr(ta) );
3236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_CMPS ( Int sz, IRTemp t_inc )
3242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty  = szToITy(sz);
3244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tdv = newTemp(ty);      /* (EDI) */
3245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tsv = newTemp(ty);      /* (ESI) */
3246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp td  = newTemp(Ity_I32); /*  EDI  */
3247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ts  = newTemp(Ity_I32); /*  ESI  */
3248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( td, getIReg(4, R_EDI) );
3250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ts, getIReg(4, R_ESI) );
3251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tdv, loadLE(ty,mkexpr(td)) );
3253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tsv, loadLE(ty,mkexpr(ts)) );
3254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
3256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_SCAS ( Int sz, IRTemp t_inc )
3263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty  = szToITy(sz);
3265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ta  = newTemp(ty);       /*  EAX  */
3266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp td  = newTemp(Ity_I32);  /*  EDI  */
3267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tdv = newTemp(ty);       /* (EDI) */
3268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ta, getIReg(sz, R_EAX) );
3270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( td, getIReg(4, R_EDI) );
3271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tdv, loadLE(ty,mkexpr(td)) );
3273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
3274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Wrap the appropriate string op inside a REP/REPE/REPNE.
3280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   We assume the insn is the last one in the basic block, and so emit a jump
3281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to the next insn, rather than just falling through. */
3282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3283663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengvoid dis_REP_op ( /*MOD*/DisResult* dres,
3284663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                  X86Condcode cond,
3285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  void (*dis_OP)(Int, IRTemp),
3286436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  Int sz, Addr32 eip, Addr32 eip_next, const HChar* name )
3287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t_inc = newTemp(Ity_I32);
3289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tc    = newTemp(Ity_I32);  /*  ECX  */
3290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tc, getIReg(4,R_ECX) );
3292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
3294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ijk_Boring,
3295663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                      IRConst_U32(eip_next), OFFB_EIP ) );
3296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
3298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dis_string_op_increment(sz, t_inc);
3300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dis_OP (sz, t_inc);
3301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cond == X86CondAlways) {
3303663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      jmp_lit(dres, Ijk_Boring, eip);
3304663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vassert(dres->whatNext == Dis_StopHere);
3305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
3307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Ijk_Boring,
3308663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         IRConst_U32(eip), OFFB_EIP ) );
3309663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      jmp_lit(dres, Ijk_Boring, eip_next);
3310663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vassert(dres->whatNext == Dis_StopHere);
3311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%c\n", name, nameISize(sz));
3313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Arithmetic, etc.                                     ---*/
3318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* IMUL E, G.  Supplied eip points to the modR/M byte. */
3321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_mul_E_G ( UChar       sorb,
3323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         size,
3324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Int         delta0 )
3325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    alen;
3327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
3328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  rm = getIByte(delta0);
3329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(size);
3330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp te = newTemp(ty);
3331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tg = newTemp(ty);
3332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp resLo = newTemp(ty);
3333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tg, getIReg(size, gregOfRM(rm)) );
3335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
3336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( te, getIReg(size, eregOfRM(rm)) );
3337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( te, loadLE(ty,mkexpr(addr)) );
3340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
3343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
3345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
3349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("imul%c %s, %s\n", nameISize(size),
3350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             nameIReg(size,eregOfRM(rm)),
3351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             nameIReg(size,gregOfRM(rm)));
3352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
3353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("imul%c %s, %s\n", nameISize(size),
3355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             dis_buf, nameIReg(size,gregOfRM(rm)));
3356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return alen+delta0;
3357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* IMUL I * E -> G.  Supplied eip points to the modR/M byte. */
3362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_imul_I_E_G ( UChar       sorb,
3364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Int         size,
3365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Int         delta,
3366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Int         litsize )
3367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    d32, alen;
3369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
3370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  rm = getIByte(delta);
3371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(size);
3372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp te = newTemp(ty);
3373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tl = newTemp(ty);
3374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp resLo = newTemp(ty);
3375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(size == 1 || size == 2 || size == 4);
3377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
3379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(te, getIReg(size, eregOfRM(rm)));
3380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
3381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(te, loadLE(ty, mkexpr(addr)));
3384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
3385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   d32 = getSDisp(litsize,delta);
3387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta += litsize;
3388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (size == 1) d32 &= 0xFF;
3390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (size == 2) d32 &= 0xFFFF;
3391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(tl, mkU(ty,d32));
3393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
3395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
3397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(size, gregOfRM(rm), mkexpr(resLo));
3399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("imul %d, %s, %s\n", d32,
3401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameIReg(size,gregOfRM(rm)) );
3403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
3404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate an IR sequence to do a count-leading-zeroes operation on
3408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the supplied IRTemp, and return a new IRTemp holding the result.
3409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'ty' may be Ity_I16 or Ity_I32 only.  In the case where the
3410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   argument is zero, return the number of bits in the word (the
3411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   natural semantics). */
3412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp gen_LZCNT ( IRType ty, IRTemp src )
3413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(ty == Ity_I32 || ty == Ity_I16);
3415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src32 = newTemp(Ity_I32);
3417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(src32, widenUto32( mkexpr(src) ));
3418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src32x = newTemp(Ity_I32);
3420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(src32x,
3421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Shl32, mkexpr(src32),
3422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU8(32 - 8 * sizeofIRType(ty))));
3423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Clz32 has undefined semantics when its input is zero, so
3425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // special-case around that.
3426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res32 = newTemp(Ity_I32);
3427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(res32,
3428436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov          IRExpr_ITE(
3429436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             binop(Iop_CmpEQ32, mkexpr(src32x), mkU32(0)),
3430436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             mkU32(8 * sizeofIRType(ty)),
3431436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             unop(Iop_Clz32, mkexpr(src32x))
3432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ));
3433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res = newTemp(ty);
3435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(res, narrowTo(ty, mkexpr(res32)));
3436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
3437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
3442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- x87 FLOATING POINT INSTRUCTIONS                      ---*/
3443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
3444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Helper functions for dealing with the register stack. --- */
3447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Set the emulation-warning pseudo-register. --- */
3449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
3453436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   stmt( IRStmt_Put( OFFB_EMNOTE, e ) );
3454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
3457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkQNaN64 ( void )
3459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* QNaN is 0 2047 1 0(51times)
3461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     == 0b 11111111111b 1 0(51times)
3462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     == 0x7FF8 0000 0000 0000
3463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
3464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
3465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/put the top-of-stack pointer. --------- */
3468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_ftop ( void )
3470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_ftop ( IRExpr* e )
3475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
3477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_FTOP, e ) );
3478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/put the C3210 bits. --------- */
3481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_C3210 ( void )
3483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( OFFB_FC3210, Ity_I32 );
3485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_C3210 ( IRExpr* e )
3488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_FC3210, e ) );
3490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/put the FPU rounding mode. --------- */
3493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* /* :: Ity_I32 */ get_fpround ( void )
3494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
3496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
3499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_FPROUND, e ) );
3501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
3505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Produces a value in 0 .. 3, which is encoded as per the type
3506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRoundingMode.  Since the guest_FPROUND value is also encoded as
3507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   per IRRoundingMode, we merely need to get it and mask it for
3508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   safety.
3509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return binop( Iop_And32, get_fpround(), mkU32(3) );
3513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
3516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return mkU32(Irrm_NEAREST);
3518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/set FP register tag bytes. --------- */
3522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_ST_TAG ( Int i, IRExpr* value )
3526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr;
3528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_I8);
3529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
3530663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   stmt( IRStmt_PutI( mkIRPutI(descr, get_ftop(), i, value) ) );
3531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, generate an expression yielding 'ST_TAG(i)'.  This will be
3534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   zero to indicate "Empty" and nonzero to indicate "NonEmpty".  */
3535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_ST_TAG ( Int i )
3537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
3539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_GetI( descr, get_ftop(), i );
3540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/set FP registers. --------- */
3544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, and some expression e, emit 'ST(i) = e' and set the
3546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register's tag to indicate the register is full.  The previous
3547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   state of the register is not checked. */
3548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_ST_UNCHECKED ( Int i, IRExpr* value )
3550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr;
3552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_F64);
3553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
3554663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   stmt( IRStmt_PutI( mkIRPutI(descr, get_ftop(), i, value) ) );
3555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Mark the register as in-use. */
3556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_TAG(i, mkU8(1));
3557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, and some expression e, emit
3560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ST(i) = is_full(i) ? NaN : e
3561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and set the tag accordingly.
3562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_ST ( Int i, IRExpr* value )
3565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3566436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   put_ST_UNCHECKED(
3567436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      i,
3568436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      IRExpr_ITE( binop(Iop_CmpNE8, get_ST_TAG(i), mkU8(0)),
3569436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  /* non-0 means full */
3570436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  mkQNaN64(),
3571436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  /* 0 means empty */
3572436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  value
3573436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      )
3574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
3575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, generate an expression yielding 'ST(i)'. */
3579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_ST_UNCHECKED ( Int i )
3581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
3583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_GetI( descr, get_ftop(), i );
3584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, generate an expression yielding
3588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  is_full(i) ? ST(i) : NaN
3589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_ST ( Int i )
3592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
3594436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      IRExpr_ITE( binop(Iop_CmpNE8, get_ST_TAG(i), mkU8(0)),
3595436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  /* non-0 means full */
3596436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  get_ST_UNCHECKED(i),
3597436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  /* 0 means empty */
3598436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  mkQNaN64());
3599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3602eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov/* Given i, and some expression e, and a condition cond, generate IR
3603eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   which has the same effect as put_ST(i,e) when cond is true and has
3604eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   no effect when cond is false.  Given the lack of proper
3605eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   if-then-else in the IR, this is pretty tricky.
3606eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov*/
3607eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
3608eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanovstatic void maybe_put_ST ( IRTemp cond, Int i, IRExpr* value )
3609eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov{
3610eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   // new_tag = if cond then FULL else old_tag
3611eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   // new_val = if cond then (if old_tag==FULL then NaN else val)
3612eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   //                   else old_val
3613eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
3614eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   IRTemp old_tag = newTemp(Ity_I8);
3615eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   assign(old_tag, get_ST_TAG(i));
3616eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   IRTemp new_tag = newTemp(Ity_I8);
3617eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   assign(new_tag,
3618eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov          IRExpr_ITE(mkexpr(cond), mkU8(1)/*FULL*/, mkexpr(old_tag)));
3619eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
3620eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   IRTemp old_val = newTemp(Ity_F64);
3621eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   assign(old_val, get_ST_UNCHECKED(i));
3622eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   IRTemp new_val = newTemp(Ity_F64);
3623eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   assign(new_val,
3624eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov          IRExpr_ITE(mkexpr(cond),
3625eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                     IRExpr_ITE(binop(Iop_CmpNE8, mkexpr(old_tag), mkU8(0)),
3626eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                                /* non-0 means full */
3627eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                                mkQNaN64(),
3628eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                                /* 0 means empty */
3629eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                                value),
3630eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                     mkexpr(old_val)));
3631eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
3632eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   put_ST_UNCHECKED(i, mkexpr(new_val));
3633eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   // put_ST_UNCHECKED incorrectly sets tag(i) to always be FULL.  So
3634eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   // now set it to new_tag instead.
3635eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   put_ST_TAG(i, mkexpr(new_tag));
3636eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov}
3637eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
3638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Adjust FTOP downwards by one register. */
3639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void fp_push ( void )
3641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
3643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3645eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov/* Adjust FTOP downwards by one register when COND is 1:I1.  Else
3646eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   don't change it. */
3647eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
3648eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanovstatic void maybe_fp_push ( IRTemp cond )
3649eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov{
3650eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   put_ftop( binop(Iop_Sub32, get_ftop(), unop(Iop_1Uto32,mkexpr(cond))) );
3651eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov}
3652eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
3653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Adjust FTOP upwards by one register, and mark the vacated register
3654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   as empty.  */
3655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void fp_pop ( void )
3657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_TAG(0, mkU8(0));
3659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
3660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3662eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov/* Set the C2 bit of the FPU status register to e[0].  Assumes that
3663eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   e[31:1] == 0.
3664eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov*/
3665eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanovstatic void set_C2 ( IRExpr* e )
3666eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov{
3667eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   IRExpr* cleared = binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2));
3668eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   put_C3210( binop(Iop_Or32,
3669eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                    cleared,
3670eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                    binop(Iop_Shl32, e, mkU8(X86G_FC_SHIFT_C2))) );
3671eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov}
3672eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
3673eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov/* Generate code to check that abs(d64) < 2^63 and is finite.  This is
3674eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   used to do the range checks for FSIN, FCOS, FSINCOS and FPTAN.  The
3675eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   test is simple, but the derivation of it is not so simple.
3676eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
3677eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   The exponent field for an IEEE754 double is 11 bits.  That means it
3678eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   can take values 0 through 0x7FF.  If the exponent has value 0x7FF,
3679eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   the number is either a NaN or an Infinity and so is not finite.
3680eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   Furthermore, a finite value of exactly 2^63 is the smallest value
3681eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   that has exponent value 0x43E.  Hence, what we need to do is
3682eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   extract the exponent, ignoring the sign bit and mantissa, and check
3683eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   it is < 0x43E, or <= 0x43D.
3684eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
3685eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   To make this easily applicable to 32- and 64-bit targets, a
3686eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   roundabout approach is used.  First the number is converted to I64,
3687eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   then the top 32 bits are taken.  Shifting them right by 20 bits
3688eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   places the sign bit and exponent in the bottom 12 bits.  Anding
3689eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   with 0x7FF gets rid of the sign bit, leaving just the exponent
3690eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   available for comparison.
3691eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov*/
3692eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanovstatic IRTemp math_IS_TRIG_ARG_FINITE_AND_IN_RANGE ( IRTemp d64 )
3693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3694eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   IRTemp i64 = newTemp(Ity_I64);
3695eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   assign(i64, unop(Iop_ReinterpF64asI64, mkexpr(d64)) );
3696eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   IRTemp exponent = newTemp(Ity_I32);
3697eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   assign(exponent,
3698eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov          binop(Iop_And32,
3699eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                binop(Iop_Shr32, unop(Iop_64HIto32, mkexpr(i64)), mkU8(20)),
3700eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                mkU32(0x7FF)));
3701eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   IRTemp in_range_and_finite = newTemp(Ity_I1);
3702eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   assign(in_range_and_finite,
3703eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov          binop(Iop_CmpLE32U, mkexpr(exponent), mkU32(0x43D)));
3704eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   return in_range_and_finite;
3705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Invent a plausible-looking FPU status word value:
3708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ((ftop & 7) << 11) | (c3210 & 0x4700)
3709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
3710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_FPU_sw ( void )
3711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
3713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unop(Iop_32to16,
3714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_Or32,
3715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Shl32,
3716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And32, get_ftop(), mkU32(7)),
3717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU8(11)),
3718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And32, get_C3210(), mkU32(0x4700))
3719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ));
3720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------------------------------------------------- */
3724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given all that stack-mangling junk, we can now go ahead
3725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and describe FP instructions.
3726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ST(0) = ST(0) `op` mem64/32(addr)
3729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Need to check ST(0)'s tag on read, but not on write.
3730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3732436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovvoid fp_do_op_mem_ST_0 ( IRTemp addr, const HChar* op_txt, HChar* dis_buf,
3733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IROp op, Bool dbl )
3734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
3736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (dbl) {
3737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ST_UNCHECKED(0,
3738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         triop( op,
3739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_ST(0),
3741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                loadLE(Ity_F64,mkexpr(addr))
3742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
3743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ST_UNCHECKED(0,
3745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         triop( op,
3746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_ST(0),
3748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
3750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ST(0) = mem64/32(addr) `op` ST(0)
3755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Need to check ST(0)'s tag on read, but not on write.
3756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3758436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovvoid fp_do_oprev_mem_ST_0 ( IRTemp addr, const HChar* op_txt, HChar* dis_buf,
3759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            IROp op, Bool dbl )
3760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
3762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (dbl) {
3763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ST_UNCHECKED(0,
3764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         triop( op,
3765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                loadLE(Ity_F64,mkexpr(addr)),
3767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_ST(0)
3768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
3769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ST_UNCHECKED(0,
3771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         triop( op,
3772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_ST(0)
3775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
3776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ST(dst) = ST(dst) `op` ST(src).
3781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Check dst and src tags when reading but not on write.
3782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3784436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovvoid fp_do_op_ST_ST ( const HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
3785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Bool pop_after )
3786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 (Int)st_src, (Int)st_dst );
3789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_UNCHECKED(
3790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      st_dst,
3791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      triop( op,
3792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_ST(st_dst),
3794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_ST(st_src) )
3795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
3796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pop_after)
3797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fp_pop();
3798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ST(dst) = ST(src) `op` ST(dst).
3801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Check dst and src tags when reading but not on write.
3802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3804436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovvoid fp_do_oprev_ST_ST ( const HChar* op_txt, IROp op, UInt st_src,
3805436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         UInt st_dst, Bool pop_after )
3806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 (Int)st_src, (Int)st_dst );
3809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_UNCHECKED(
3810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      st_dst,
3811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      triop( op,
3812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_ST(st_src),
3814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_ST(st_dst) )
3815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
3816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pop_after)
3817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fp_pop();
3818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", (Int)i );
3824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is a bit of a hack (and isn't really right).  It sets
3825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      documentation implies A and S are unchanged.
3827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
3828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* It's also fishy in that it is used both for COMIP and
3829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UCOMIP, and they aren't the same (although similar). */
3830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
3831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
3832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1,
3833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop( Iop_And32,
3834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(0x45)
3836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       )));
3837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
3838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
3839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
3840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pop_after)
3841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fp_pop();
3842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
3847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    len;
3849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   r_src, r_dst;
3850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
3851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1, t2;
3852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* On entry, delta points at the second byte of the insn (the modrm
3854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      byte).*/
3855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar first_opcode = getIByte(delta-1);
3856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar modrm        = getIByte(delta+0);
3857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xD8) {
3861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
3862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
3864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           specifies an address. */
3865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
3867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
3869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FADD single-real */
3871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FMUL single-real */
3875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FCOM single-real */
3879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcoms %s\n", dis_buf);
3880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
3881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
3882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
3883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
3884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
3885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
3886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      unop(Iop_F32toF64,
3887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           loadLE(Ity_F32,mkexpr(addr)))),
3888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
3889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
3890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
3891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FCOMP single-real */
3894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcomps %s\n", dis_buf);
3895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
3896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
3897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
3898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
3899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
3900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
3901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      unop(Iop_F32toF64,
3902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           loadLE(Ity_F32,mkexpr(addr)))),
3903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
3904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
3905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
3906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
3907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: /* FSUB single-real */
3910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FSUBR single-real */
3914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: /* FDIV single-real */
3918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FDIVR single-real */
3922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
3926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xD8\n");
3928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
3929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
3931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
3932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
3933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
3935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
3936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Dunno if this is right */
3943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xD0;
3945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcom %%st(0),%%st(%d)\n", (Int)r_dst);
3946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
3947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
3948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
3949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
3950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
3952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
3953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
3954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Dunno if this is right */
3957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xD8;
3959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcomp %%st(0),%%st(%d)\n", (Int)r_dst);
3960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
3961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
3962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
3963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
3964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
3966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
3967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
3968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
3969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
3972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
3973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
3986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
3988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
3989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
3995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xD9) {
3996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
3997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
3999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
4000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
4002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
4004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FLD single-real */
4006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("flds %s\n", dis_buf);
4007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, unop(Iop_F32toF64,
4009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              loadLE(Ity_F32, mkexpr(addr))));
4010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FST single-real */
4013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fsts %s\n", dis_buf);
4014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr),
4015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FSTP single-real */
4019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstps %s\n", dis_buf);
4020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr),
4021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: { /* FLDENV m28 */
4026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
4027436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                     VexEmNote x86g_do_FLDENV ( VexGuestX86State*, HWord ) */
4028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp   ew = newTemp(Ity_I32);
4029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d  = unsafeIRDirty_0_N (
4030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                0/*regparms*/,
4031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                "x86g_dirtyhelper_FLDENV",
4032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                &x86g_dirtyhelper_FLDENV,
4033436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
4034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             );
4035436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               d->tmp   = ew;
4036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're reading memory */
4037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Read;
4038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
4039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 28;
4040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing guest state */
4042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->nFxState = 4;
4043663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               vex_bzero(&d->fxState, sizeof(d->fxState));
4044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].fx     = Ifx_Write;
4046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].offset = OFFB_FTOP;
4047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].size   = sizeof(UInt);
4048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].fx     = Ifx_Write;
4050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].offset = OFFB_FPTAGS;
4051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].size   = 8 * sizeof(UChar);
4052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].fx     = Ifx_Write;
4054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].offset = OFFB_FPROUND;
4055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].size   = sizeof(UInt);
4056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].fx     = Ifx_Write;
4058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].offset = OFFB_FC3210;
4059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].size   = sizeof(UInt);
4060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
4062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* ew contains any emulation warning we may need to
4064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  issue.  If needed, side-exit to the next insn,
4065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  reporting the warning, so that Valgrind's dispatcher
4066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  sees the warning. */
4067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_emwarn( mkexpr(ew) );
4068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt(
4069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRStmt_Exit(
4070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_EmWarn,
4072663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
4073663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     OFFB_EIP
4074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
4075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
4076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldenv %s\n", dis_buf);
4078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: {/* FLDCW */
4082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* The only thing we observe in the control word is the
4083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  rounding mode.  Therefore, pass the 16-bit value
4084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (x87 native-format control word) to a clean helper,
4085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getting back a 64-bit value, the lower half of which
4086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  is the FPROUND value to store, and the upper half of
4087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  which is the emulation-warning token which may be
4088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  generated.
4089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               */
4090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* ULong x86h_check_fldcw ( UInt ); */
4091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp t64 = newTemp(Ity_I64);
4092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp ew = newTemp(Ity_I32);
4093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldcw %s\n", dis_buf);
4094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( t64, mkIRExprCCall(
4095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               Ity_I64, 0/*regparms*/,
4096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "x86g_check_fldcw",
4097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &x86g_check_fldcw,
4098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkIRExprVec_1(
4099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  unop( Iop_16Uto32,
4100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        loadLE(Ity_I16, mkexpr(addr)))
4101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               )
4102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            )
4103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
4104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_fpround( unop(Iop_64to32, mkexpr(t64)) );
4106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
4107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_emwarn( mkexpr(ew) );
4108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Finally, if an emulation warning was reported,
4109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  side-exit to the next insn, reporting the warning,
4110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  so that Valgrind's dispatcher sees the warning. */
4111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt(
4112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRStmt_Exit(
4113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_EmWarn,
4115663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
4116663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     OFFB_EIP
4117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
4118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
4119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: { /* FNSTENV m28 */
4123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
4124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     void x86g_do_FSTENV ( VexGuestX86State*, HWord ) */
4125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d = unsafeIRDirty_0_N (
4126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               0/*regparms*/,
4127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "x86g_dirtyhelper_FSTENV",
4128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &x86g_dirtyhelper_FSTENV,
4129436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                               mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
4130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            );
4131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing memory */
4132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Write;
4133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
4134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 28;
4135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're reading guest state */
4137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->nFxState = 4;
4138663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               vex_bzero(&d->fxState, sizeof(d->fxState));
4139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].fx     = Ifx_Read;
4141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].offset = OFFB_FTOP;
4142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].size   = sizeof(UInt);
4143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].fx     = Ifx_Read;
4145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].offset = OFFB_FPTAGS;
4146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].size   = 8 * sizeof(UChar);
4147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].fx     = Ifx_Read;
4149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].offset = OFFB_FPROUND;
4150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].size   = sizeof(UInt);
4151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].fx     = Ifx_Read;
4153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].offset = OFFB_FC3210;
4154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].size   = sizeof(UInt);
4155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
4157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnstenv %s\n", dis_buf);
4159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FNSTCW */
4163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              /* Fake up a native x87 FPU control word.  The only
4164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 thing it depends on is FPROUND[1:0], so call a clean
4165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 helper to cook it up. */
4166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* UInt x86h_create_fpucw ( UInt fpround ) */
4167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnstcw %s\n", dis_buf);
4168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(
4169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkexpr(addr),
4170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop( Iop_32to16,
4171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkIRExprCCall(
4172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Ity_I32, 0/*regp*/,
4173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           "x86g_create_fpucw", &x86g_create_fpucw,
4174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkIRExprVec_1( get_fpround() )
4175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        )
4176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
4177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
4178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xD9\n");
4183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
4187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
4188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
4189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FLD %st(?) */
4191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC0;
4192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fld %%st(%d)\n", (Int)r_src);
4193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               t1 = newTemp(Ity_F64);
4194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(t1, get_ST(r_src));
4195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, mkexpr(t1));
4197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FXCH %st(?) */
4200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC8;
4201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fxch %%st(%d)\n", (Int)r_src);
4202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               t1 = newTemp(Ity_F64);
4203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               t2 = newTemp(Ity_F64);
4204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(t1, get_ST(0));
4205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(t2, get_ST(r_src));
4206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0, mkexpr(t2));
4207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(r_src, mkexpr(t1));
4208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0: /* FCHS */
4211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fchs\n");
4212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE1: /* FABS */
4216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fabs\n");
4217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE4: /* FTST */
4221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ftst\n");
4222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Well, in fact the Intel docs say (bizarrely): "C1 is
4224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  set to 0 if stack underflow occurred; otherwise, set
4225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  to 0" which is pretty nonsensical.  I guess it's a
4226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   typo. */
4227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
4229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
4230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
4231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
4232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRExpr_Const(IRConst_F64i(0x0ULL))),
4233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
4234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
4235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
4236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE5: { /* FXAM */
4239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This is an interesting one.  It examines %st(0),
4240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  regardless of whether the tag says it's empty or not.
4241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Here, just pass both the tag (in our format) and the
4242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  value (as a double, actually a ULong) to a helper
4243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  function. */
4244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr** args
4245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
4246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   unop(Iop_ReinterpF64asI64,
4247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        get_ST_UNCHECKED(0)) );
4248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(mkIRExprCCall(
4249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Ity_I32,
4250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            0/*regparm*/,
4251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            "x86g_calculate_FXAM", &x86g_calculate_FXAM,
4252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            args
4253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        ));
4254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fxam\n");
4255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8: /* FLD1 */
4259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fld1\n");
4260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
4262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
4263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE9: /* FLDL2T */
4266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldl2t\n");
4267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
4269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
4270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xEA: /* FLDL2E */
4273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldl2e\n");
4274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
4276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
4277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xEB: /* FLDPI */
4280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldpi\n");
4281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
4283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
4284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xEC: /* FLDLG2 */
4287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldlg2\n");
4288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
4290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
4291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xED: /* FLDLN2 */
4294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldln2\n");
4295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
4297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
4298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xEE: /* FLDZ */
4301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldz\n");
4302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
4304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
4305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0: /* F2XM1 */
4308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("f2xm1\n");
4309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_2xm1F64,
4311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF1: /* FYL2X */
4316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fyl2x\n");
4317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(1,
4318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_Yl2xF64,
4319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(1),
4321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4325eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            case 0xF2: { /* FPTAN */
4326eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               DIP("fptan\n");
4327eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               IRTemp argD = newTemp(Ity_F64);
4328eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               assign(argD, get_ST(0));
4329eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4330eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               IRTemp resD = newTemp(Ity_F64);
4331eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               assign(resD,
4332eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                  IRExpr_ITE(
4333eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                     mkexpr(argOK),
4334eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                     binop(Iop_TanF64,
4335eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                           get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4336eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                           mkexpr(argD)),
4337eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                     mkexpr(argD))
4338eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               );
4339eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               put_ST_UNCHECKED(0, mkexpr(resD));
4340eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               /* Conditionally push 1.0 on the stack, if the arg is
4341eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                  in range */
4342eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               maybe_fp_push(argOK);
4343eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               maybe_put_ST(argOK, 0,
4344eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                            IRExpr_Const(IRConst_F64(1.0)));
4345eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               set_C2( binop(Iop_Xor32,
4346eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                             unop(Iop_1Uto32, mkexpr(argOK)),
4347eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                             mkU32(1)) );
4348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4349eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            }
4350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF3: /* FPATAN */
4352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fpatan\n");
4353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(1,
4354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_AtanF64,
4355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(1),
4357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF4: { /* FXTRACT */
4362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp argF = newTemp(Ity_F64);
4363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp sigF = newTemp(Ity_F64);
4364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp expF = newTemp(Ity_F64);
4365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp argI = newTemp(Ity_I64);
4366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp sigI = newTemp(Ity_I64);
4367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp expI = newTemp(Ity_I64);
4368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fxtract\n");
4369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( argF, get_ST(0) );
4370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
4371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( sigI,
4372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprCCall(
4373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Ity_I64, 0/*regparms*/,
4374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "x86amd64g_calculate_FXTRACT",
4375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          &x86amd64g_calculate_FXTRACT,
4376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkIRExprVec_2( mkexpr(argI),
4377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkIRExpr_HWord(0)/*sig*/ ))
4378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
4379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( expI,
4380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprCCall(
4381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Ity_I64, 0/*regparms*/,
4382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "x86amd64g_calculate_FXTRACT",
4383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          &x86amd64g_calculate_FXTRACT,
4384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkIRExprVec_2( mkexpr(argI),
4385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkIRExpr_HWord(1)/*exp*/ ))
4386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
4387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
4388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
4389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* exponent */
4390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0, mkexpr(expF) );
4391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* significand */
4393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, mkexpr(sigF) );
4394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF5: { /* FPREM1 -- IEEE compliant */
4398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a1 = newTemp(Ity_F64);
4399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a2 = newTemp(Ity_F64);
4400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fprem1\n");
4401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Do FPREM1 twice, once to get the remainder, and once
4402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  to get the C3210 flag values. */
4403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a1, get_ST(0) );
4404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a2, get_ST(1) );
4405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_PRem1F64,
4407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1),
4409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a2)));
4410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_PRem1C3210F64,
4412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1),
4414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a2)) );
4415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF7: /* FINCSTP */
4419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fprem\n");
4420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF8: { /* FPREM -- not IEEE compliant */
4424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a1 = newTemp(Ity_F64);
4425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a2 = newTemp(Ity_F64);
4426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fprem\n");
4427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Do FPREM twice, once to get the remainder, and once
4428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  to get the C3210 flag values. */
4429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a1, get_ST(0) );
4430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a2, get_ST(1) );
4431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_PRemF64,
4433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1),
4435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a2)));
4436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_PRemC3210F64,
4438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1),
4440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a2)) );
4441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF9: /* FYL2XP1 */
4445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fyl2xp1\n");
4446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(1,
4447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_Yl2xp1F64,
4448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(1),
4450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFA: /* FSQRT */
4455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fsqrt\n");
4456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_SqrtF64,
4458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFB: { /* FSINCOS */
4463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fsincos\n");
4464eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               IRTemp argD = newTemp(Ity_F64);
4465eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               assign(argD, get_ST(0));
4466eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4467eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               IRTemp resD = newTemp(Ity_F64);
4468eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               assign(resD,
4469eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                  IRExpr_ITE(
4470eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                     mkexpr(argOK),
4471eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                     binop(Iop_SinF64,
4472eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                           get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4473eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                           mkexpr(argD)),
4474eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                     mkexpr(argD))
4475eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               );
4476eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               put_ST_UNCHECKED(0, mkexpr(resD));
4477eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               /* Conditionally push the cos value on the stack, if
4478eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                  the arg is in range */
4479eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               maybe_fp_push(argOK);
4480eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               maybe_put_ST(argOK, 0,
4481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_CosF64,
4482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4483eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                        mkexpr(argD)));
4484eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               set_C2( binop(Iop_Xor32,
4485eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                             unop(Iop_1Uto32, mkexpr(argOK)),
4486eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                             mkU32(1)) );
4487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFC: /* FRNDINT */
4491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("frndint\n");
4492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
4494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFD: /* FSCALE */
4497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fscale\n");
4498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_ScaleF64,
4500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0),
4502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(1)));
4503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4505eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            case 0xFE:   /* FSIN */
4506eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            case 0xFF: { /* FCOS */
4507eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               Bool isSIN = modrm == 0xFE;
4508eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               DIP("%s\n", isSIN ? "fsin" : "fcos");
4509eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               IRTemp argD = newTemp(Ity_F64);
4510eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               assign(argD, get_ST(0));
4511eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4512eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               IRTemp resD = newTemp(Ity_F64);
4513eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               assign(resD,
4514eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                  IRExpr_ITE(
4515eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                     mkexpr(argOK),
4516eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                     binop(isSIN ? Iop_SinF64 : Iop_CosF64,
4517eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                           get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4518eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                           mkexpr(argD)),
4519eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                     mkexpr(argD))
4520eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               );
4521eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               put_ST_UNCHECKED(0, mkexpr(resD));
4522eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               set_C2( binop(Iop_Xor32,
4523eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                             unop(Iop_1Uto32, mkexpr(argOK)),
4524eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                             mkU32(1)) );
4525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4526eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            }
4527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
4536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDA) {
4537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
4539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
4541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
4542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   fop;
4543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
4545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
4546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FIADD m32int */ /* ST(0) += m32int */
4548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fiaddl %s\n", dis_buf);
4549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_AddF64;
4550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m32;
4551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
4553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fimull %s\n", dis_buf);
4554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_MulF64;
4555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m32;
4556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FICOM m32int */
4558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ficoml %s\n", dis_buf);
4559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
4562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
4563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
4564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
4565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      unop(Iop_I32StoF64,
4566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           loadLE(Ity_I32,mkexpr(addr)))),
4567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
4568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
4569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
4570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FICOMP m32int */
4573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ficompl %s\n", dis_buf);
4574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
4577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
4578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
4579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
4580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      unop(Iop_I32StoF64,
4581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           loadLE(Ity_I32,mkexpr(addr)))),
4582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
4583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
4584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
4585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: /* FISUB m32int */ /* ST(0) -= m32int */
4589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubl %s\n", dis_buf);
4590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_SubF64;
4591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m32;
4592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
4594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubrl %s\n", dis_buf);
4595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_SubF64;
4596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_foprev_m32;
4597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
4599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fidivl %s\n", dis_buf);
4600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_DivF64;
4601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m32;
4602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
4604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fidivrl %s\n", dis_buf);
4605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_DivF64;
4606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_foprev_m32;
4607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do_fop_m32:
4609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(fop,
4611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0),
4613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_I32StoF64,
4614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             loadLE(Ity_I32, mkexpr(addr)))));
4615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do_foprev_m32:
4618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(fop,
4620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_I32StoF64,
4622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             loadLE(Ity_I32, mkexpr(addr))),
4623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
4624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDA\n");
4629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
4633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
4635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
4636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC0;
4639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovb %%st(%d), %%st(0)\n", (Int)r_src);
4640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4641436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                IRExpr_ITE(
4642436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    mk_x86g_calculate_condition(X86CondB),
4643436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    get_ST(r_src), get_ST(0)) );
4644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC8;
4648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovz %%st(%d), %%st(0)\n", (Int)r_src);
4649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4650436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                IRExpr_ITE(
4651436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    mk_x86g_calculate_condition(X86CondZ),
4652436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    get_ST(r_src), get_ST(0)) );
4653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xD0;
4657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovbe %%st(%d), %%st(0)\n", (Int)r_src);
4658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4659436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                IRExpr_ITE(
4660436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    mk_x86g_calculate_condition(X86CondBE),
4661436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    get_ST(r_src), get_ST(0)) );
4662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
4665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xD8;
4666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovu %%st(%d), %%st(0)\n", (Int)r_src);
4667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4668436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                IRExpr_ITE(
4669436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    mk_x86g_calculate_condition(X86CondP),
4670436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    get_ST(r_src), get_ST(0)) );
4671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE9: /* FUCOMPP %st(0),%st(1) */
4674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fucompp %%st(0),%%st(1)\n");
4675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
4678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
4679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
4681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
4682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
4683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
4696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDB) {
4697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
4698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
4700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
4701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
4703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
4705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FILD m32int */
4707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fildl %s\n", dis_buf);
4708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, unop(Iop_I32StoF64,
4710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              loadLE(Ity_I32, mkexpr(addr))));
4711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FISTTPL m32 (SSE3) */
4714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisttpl %s\n", dis_buf);
4715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
4716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) );
4717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FIST m32 */
4721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistl %s\n", dis_buf);
4722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
4723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
4724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FISTP m32 */
4727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistpl %s\n", dis_buf);
4728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
4729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
4730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: { /* FLD extended-real */
4734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
4735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ULong x86g_loadF80le ( UInt )
4736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  addr holds the address.  First, do a dirty call to
4737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  get hold of the data. */
4738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp   val  = newTemp(Ity_I64);
4739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d = unsafeIRDirty_1_N (
4742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               val,
4743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               0/*regparms*/,
4744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "x86g_dirtyhelper_loadF80le",
4745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &x86g_dirtyhelper_loadF80le,
4746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               args
4747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            );
4748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare that we're reading memory */
4749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Read;
4750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
4751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 10;
4752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* execute the dirty call, dumping the result in val. */
4754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
4755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
4756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldt %s\n", dis_buf);
4759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: { /* FSTP extended-real */
4763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
4764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr** args
4765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  = mkIRExprVec_2( mkexpr(addr),
4766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   unop(Iop_ReinterpF64asI64, get_ST(0)) );
4767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d = unsafeIRDirty_0_N (
4769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               0/*regparms*/,
4770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "x86g_dirtyhelper_storeF80le",
4771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &x86g_dirtyhelper_storeF80le,
4772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               args
4773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            );
4774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing memory */
4775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Write;
4776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
4777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 10;
4778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* execute the dirty call. */
4780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
4781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstpt\n %s", dis_buf);
4784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDB\n");
4790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
4794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
4796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
4797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
4799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC0;
4800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovnb %%st(%d), %%st(0)\n", (Int)r_src);
4801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4802436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                IRExpr_ITE(
4803436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    mk_x86g_calculate_condition(X86CondNB),
4804436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    get_ST(r_src), get_ST(0)) );
4805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC8;
4809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovnz %%st(%d), %%st(0)\n", (Int)r_src);
4810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4811436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                IRExpr_ITE(
4812436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    mk_x86g_calculate_condition(X86CondNZ),
4813436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    get_ST(r_src), get_ST(0)) );
4814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
4817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xD0;
4818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovnbe %%st(%d), %%st(0)\n", (Int)r_src);
4819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4820436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                IRExpr_ITE(
4821436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    mk_x86g_calculate_condition(X86CondNBE),
4822436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    get_ST(r_src), get_ST(0)) );
4823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
4826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xD8;
4827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovnu %%st(%d), %%st(0)\n", (Int)r_src);
4828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
4829436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                IRExpr_ITE(
4830436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    mk_x86g_calculate_condition(X86CondNP),
4831436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    get_ST(r_src), get_ST(0)) );
4832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE2:
4835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnclex\n");
4836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE3: {
4839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
4840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     void x86g_do_FINIT ( VexGuestX86State* ) */
4841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d  = unsafeIRDirty_0_N (
4842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                0/*regparms*/,
4843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                "x86g_dirtyhelper_FINIT",
4844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                &x86g_dirtyhelper_FINIT,
4845436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                mkIRExprVec_1(IRExpr_BBPTR())
4846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             );
4847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing guest state */
4849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->nFxState = 5;
4850663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               vex_bzero(&d->fxState, sizeof(d->fxState));
4851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].fx     = Ifx_Write;
4853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].offset = OFFB_FTOP;
4854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].size   = sizeof(UInt);
4855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].fx     = Ifx_Write;
4857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].offset = OFFB_FPREGS;
4858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].size   = 8 * sizeof(ULong);
4859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].fx     = Ifx_Write;
4861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].offset = OFFB_FPTAGS;
4862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].size   = 8 * sizeof(UChar);
4863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].fx     = Ifx_Write;
4865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].offset = OFFB_FPROUND;
4866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].size   = sizeof(UInt);
4867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].fx     = Ifx_Write;
4869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].offset = OFFB_FC3210;
4870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].size   = sizeof(UInt);
4871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
4873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fninit\n");
4875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
4894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDC) {
4895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
4896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
4898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
4899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
4901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
4903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FADD double-real */
4905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FMUL double-real */
4909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FCOM double-real */
4913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcoml %s\n", dis_buf);
4914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
4917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
4918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
4919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
4920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      loadLE(Ity_F64,mkexpr(addr))),
4921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
4922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
4923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
4924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FCOMP double-real */
4927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcompl %s\n", dis_buf);
4928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
4931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
4932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
4933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
4934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      loadLE(Ity_F64,mkexpr(addr))),
4935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
4936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
4937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
4938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
4939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: /* FSUB double-real */
4942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FSUBR double-real */
4946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: /* FDIV double-real */
4950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FDIVR double-real */
4954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDC\n");
4960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
4964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
4966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
4967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
5001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDD) {
5002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
5004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
5006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
5007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
5009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
5011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FLD double-real */
5013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldl %s\n", dis_buf);
5014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
5016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FISTTPQ m64 (SSE3) */
5019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistppll %s\n", dis_buf);
5020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
5021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI64S, mkU32(Irrm_ZERO), get_ST(0)) );
5022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FST double-real */
5026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstl %s\n", dis_buf);
5027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr), get_ST(0));
5028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FSTP double-real */
5031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstpl %s\n", dis_buf);
5032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr), get_ST(0));
5033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: { /* FRSTOR m108 */
5037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
5038436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                     VexEmNote x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
5039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp   ew = newTemp(Ity_I32);
5040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d  = unsafeIRDirty_0_N (
5041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                0/*regparms*/,
5042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                "x86g_dirtyhelper_FRSTOR",
5043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                &x86g_dirtyhelper_FRSTOR,
5044436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
5045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             );
5046436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               d->tmp   = ew;
5047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're reading memory */
5048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Read;
5049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
5050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 108;
5051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing guest state */
5053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->nFxState = 5;
5054663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               vex_bzero(&d->fxState, sizeof(d->fxState));
5055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].fx     = Ifx_Write;
5057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].offset = OFFB_FTOP;
5058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].size   = sizeof(UInt);
5059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].fx     = Ifx_Write;
5061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].offset = OFFB_FPREGS;
5062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].size   = 8 * sizeof(ULong);
5063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].fx     = Ifx_Write;
5065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].offset = OFFB_FPTAGS;
5066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].size   = 8 * sizeof(UChar);
5067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].fx     = Ifx_Write;
5069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].offset = OFFB_FPROUND;
5070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].size   = sizeof(UInt);
5071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].fx     = Ifx_Write;
5073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].offset = OFFB_FC3210;
5074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].size   = sizeof(UInt);
5075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
5077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* ew contains any emulation warning we may need to
5079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  issue.  If needed, side-exit to the next insn,
5080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  reporting the warning, so that Valgrind's dispatcher
5081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  sees the warning. */
5082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_emwarn( mkexpr(ew) );
5083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt(
5084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRStmt_Exit(
5085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_EmWarn,
5087663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
5088663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     OFFB_EIP
5089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
5090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
5091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("frstor %s\n", dis_buf);
5093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: { /* FNSAVE m108 */
5097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
5098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
5099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d = unsafeIRDirty_0_N (
5100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               0/*regparms*/,
5101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "x86g_dirtyhelper_FSAVE",
5102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &x86g_dirtyhelper_FSAVE,
5103436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                               mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
5104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            );
5105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing memory */
5106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Write;
5107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
5108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 108;
5109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're reading guest state */
5111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->nFxState = 5;
5112663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               vex_bzero(&d->fxState, sizeof(d->fxState));
5113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].fx     = Ifx_Read;
5115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].offset = OFFB_FTOP;
5116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].size   = sizeof(UInt);
5117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].fx     = Ifx_Read;
5119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].offset = OFFB_FPREGS;
5120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].size   = 8 * sizeof(ULong);
5121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].fx     = Ifx_Read;
5123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].offset = OFFB_FPTAGS;
5124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].size   = 8 * sizeof(UChar);
5125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].fx     = Ifx_Read;
5127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].offset = OFFB_FPROUND;
5128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].size   = sizeof(UInt);
5129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].fx     = Ifx_Read;
5131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].offset = OFFB_FC3210;
5132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].size   = sizeof(UInt);
5133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
5135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnsave %s\n", dis_buf);
5137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: { /* FNSTSW m16 */
5141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr* sw = get_FPU_sw();
5142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(typeOfIRExpr(irsb->tyenv, sw) == Ity_I16);
5143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), sw );
5144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnstsw %s\n", dis_buf);
5145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDD\n");
5151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
5155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
5156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FFREE %st(?) */
5158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xC0;
5159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ffree %%st(%d)\n", (Int)r_dst);
5160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_TAG ( r_dst, mkU8(0) );
5161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
5164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xD0;
5165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fst %%st(0),%%st(%d)\n", (Int)r_dst);
5166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* P4 manual says: "If the destination operand is a
5167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  non-empty register, the invalid-operation exception
5168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  is not generated.  Hence put_ST_UNCHECKED. */
5169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(r_dst, get_ST(0));
5170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xD8;
5174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstp %%st(0),%%st(%d)\n", (Int)r_dst);
5175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* P4 manual says: "If the destination operand is a
5176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  non-empty register, the invalid-operation exception
5177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  is not generated.  Hence put_ST_UNCHECKED. */
5178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(r_dst, get_ST(0));
5179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xE0;
5184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fucom %%st(0),%%st(%d)\n", (Int)r_dst);
5185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
5186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
5188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
5189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
5191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
5192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
5193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xE8;
5197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fucomp %%st(0),%%st(%d)\n", (Int)r_dst);
5198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
5199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
5201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
5202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
5204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
5205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
5206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
5217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDE) {
5218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
5220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
5222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
5223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   fop;
5224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
5226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
5228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FIADD m16int */ /* ST(0) += m16int */
5230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fiaddw %s\n", dis_buf);
5231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_AddF64;
5232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m16;
5233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
5235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fimulw %s\n", dis_buf);
5236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_MulF64;
5237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m16;
5238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FICOM m16int */
5240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ficomw %s\n", dis_buf);
5241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
5242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
5244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
5245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
5246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
5247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      unop(Iop_I32StoF64,
5248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         unop(Iop_16Sto32,
5249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           loadLE(Ity_I16,mkexpr(addr))))),
5250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
5251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
5252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
5253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FICOMP m16int */
5256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ficompw %s\n", dis_buf);
5257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
5258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
5260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
5261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
5262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
5263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      unop(Iop_I32StoF64,
5264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         unop(Iop_16Sto32,
5265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              loadLE(Ity_I16,mkexpr(addr))))),
5266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
5267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
5268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
5269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: /* FISUB m16int */ /* ST(0) -= m16int */
5273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubw %s\n", dis_buf);
5274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_SubF64;
5275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m16;
5276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
5278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubrw %s\n", dis_buf);
5279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_SubF64;
5280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_foprev_m16;
5281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
5283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubw %s\n", dis_buf);
5284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_DivF64;
5285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m16;
5286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
5288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fidivrw %s\n", dis_buf);
5289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_DivF64;
5290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_foprev_m16;
5291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do_fop_m16:
5293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(fop,
5295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0),
5297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_I32StoF64,
5298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_16Sto32,
5299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  loadLE(Ity_I16, mkexpr(addr))))));
5300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do_foprev_m16:
5303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(fop,
5305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_I32StoF64,
5307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_16Sto32,
5308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  loadLE(Ity_I16, mkexpr(addr)))),
5309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
5310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDE\n");
5315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
5321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
5322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD9: /* FCOMPP %st(0),%st(1) */
5332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fuompp %%st(0),%%st(1)\n");
5333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
5334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
5336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
5337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
5339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
5340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
5341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0,  modrm - 0xE0, True );
5347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
5350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "sub", Iop_SubF64, 0,  modrm - 0xE8, True );
5351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
5370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDF) {
5371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
5373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
5375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
5376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
5378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
5380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FILD m16int */
5382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fildw %s\n", dis_buf);
5383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, unop(Iop_I32StoF64,
5385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_16Sto32,
5386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   loadLE(Ity_I16, mkexpr(addr)))));
5387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FISTTPS m16 (SSE3) */
5390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisttps %s\n", dis_buf);
5391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
5392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI16S, mkU32(Irrm_ZERO), get_ST(0)) );
5393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FIST m16 */
5397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistp %s\n", dis_buf);
5398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
5399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
5400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FISTP m16 */
5403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistps %s\n", dis_buf);
5404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
5405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
5406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FILD m64 */
5410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fildll %s\n", dis_buf);
5411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, binop(Iop_I64StoF64,
5413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               get_roundingmode(),
5414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               loadLE(Ity_I64, mkexpr(addr))));
5415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FISTP m64 */
5418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistpll %s\n", dis_buf);
5419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
5420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI64S, get_roundingmode(), get_ST(0)) );
5421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDF\n");
5427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
5433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
5434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0: /* FFREEP %st(0) */
5436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ffreep %%st(%d)\n", 0);
5437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_TAG ( 0, mkU8(0) );
5438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0: /* FNSTSW %ax */
5442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnstsw %%ax\n");
5443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Get the FPU status word value and dump it in %AX. */
5444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0) {
5445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* The obvious thing to do is simply dump the 16-bit
5446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     status word value in %AX.  However, due to a
5447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     limitation in Memcheck's origin tracking
5448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     machinery, this causes Memcheck not to track the
5449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     origin of any undefinedness into %AH (only into
5450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     %AL/%AX/%EAX), which means origins are lost in
5451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     the sequence "fnstsw %ax; test $M,%ah; jcond .." */
5452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putIReg(2, R_EAX, get_FPU_sw());
5453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
5454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* So a somewhat lame kludge is to make it very
5455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     clear to Memcheck that the value is written to
5456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     both %AH and %AL.  This generates marginally
5457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     worse code, but I don't think it matters much. */
5458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRTemp t16 = newTemp(Ity_I16);
5459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(t16, get_FPU_sw());
5460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putIReg( 1, R_AL, unop(Iop_16to8, mkexpr(t16)) );
5461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putIReg( 1, R_AH, unop(Iop_16HIto8, mkexpr(t16)) );
5462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
5463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
5466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
5467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* not really right since COMIP != UCOMIP */
5471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
5482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("dis_FPU(x86): invalid primary opcode");
5483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_ok = True;
5485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
5486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_fail:
5488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_ok = False;
5489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
5490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
5494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
5495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- MMX INSTRUCTIONS                                     ---*/
5496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
5497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
5498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Effect of MMX insns on x87 FPU state (table 11-2 of
5500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IA32 arch manual, volume 3):
5501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Read from, or write to MMX register (viz, any insn except EMMS):
5503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FP stack pointer set to zero
5505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   EMMS:
5507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FP stack pointer set to zero
5509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
5510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void do_MMX_preamble ( void )
5512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int         i;
5514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     zero  = mkU32(0);
5516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     tag1  = mkU8(1);
5517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ftop(zero);
5518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < 8; i++)
5519663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      stmt( IRStmt_PutI( mkIRPutI(descr, zero, i, tag1) ) );
5520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void do_EMMS_preamble ( void )
5523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int         i;
5525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     zero  = mkU32(0);
5527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     tag0  = mkU8(0);
5528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ftop(zero);
5529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < 8; i++)
5530663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      stmt( IRStmt_PutI( mkIRPutI(descr, zero, i, tag0) ) );
5531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getMMXReg ( UInt archreg )
5535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg < 8);
5537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putMMXReg ( UInt archreg, IRExpr* e )
5542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg < 8);
5544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
5545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for non-shift MMX insns.  Note this is incomplete in the
5550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sense that it does not first call do_MMX_preamble() -- that is the
5551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   responsibility of its caller. */
5552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
5554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_MMXop_regmem_to_reg ( UChar  sorb,
5555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               Int    delta,
5556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               UChar  opc,
5557436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                               const HChar* name,
5558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               Bool   show_granularity )
5559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
5561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   modrm = getIByte(delta);
5562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    isReg = epartIsReg(modrm);
5563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* argL  = NULL;
5564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* argR  = NULL;
5565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* argG  = NULL;
5566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* argE  = NULL;
5567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  res   = newTemp(Ity_I64);
5568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    invG  = False;
5570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    op    = Iop_INVALID;
5571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void*   hAddr = NULL;
5572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    eLeft = False;
5573436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const HChar*  hName = NULL;
5574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
5576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (opc) {
5578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Original MMX ones */
5579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFC: op = Iop_Add8x8; break;
5580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFD: op = Iop_Add16x4; break;
5581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFE: op = Iop_Add32x2; break;
5582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEC: op = Iop_QAdd8Sx8; break;
5584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xED: op = Iop_QAdd16Sx4; break;
5585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDC: op = Iop_QAdd8Ux8; break;
5587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDD: op = Iop_QAdd16Ux4; break;
5588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF8: op = Iop_Sub8x8;  break;
5590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF9: op = Iop_Sub16x4; break;
5591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFA: op = Iop_Sub32x2; break;
5592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE8: op = Iop_QSub8Sx8; break;
5594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE9: op = Iop_QSub16Sx4; break;
5595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD8: op = Iop_QSub8Ux8; break;
5597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD9: op = Iop_QSub16Ux4; break;
5598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE5: op = Iop_MulHi16Sx4; break;
5600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD5: op = Iop_Mul16x4; break;
5601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
5602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x74: op = Iop_CmpEQ8x8; break;
5604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x75: op = Iop_CmpEQ16x4; break;
5605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x76: op = Iop_CmpEQ32x2; break;
5606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x64: op = Iop_CmpGT8Sx8; break;
5608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x65: op = Iop_CmpGT16Sx4; break;
5609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x66: op = Iop_CmpGT32Sx2; break;
5610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5611b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case 0x6B: op = Iop_QNarrowBin32Sto16Sx4; eLeft = True; break;
5612b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case 0x63: op = Iop_QNarrowBin16Sto8Sx8;  eLeft = True; break;
5613b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case 0x67: op = Iop_QNarrowBin16Sto8Ux8;  eLeft = True; break;
5614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x68: op = Iop_InterleaveHI8x8;  eLeft = True; break;
5616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
5617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
5618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x60: op = Iop_InterleaveLO8x8;  eLeft = True; break;
5620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
5621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
5622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDB: op = Iop_And64; break;
5624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDF: op = Iop_And64; invG = True; break;
5625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEB: op = Iop_Or64; break;
5626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEF: /* Possibly do better here if argL and argR are the
5627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    same reg */
5628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 op = Iop_Xor64; break;
5629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Introduced in SSE1 */
5631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE0: op = Iop_Avg8Ux8;    break;
5632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE3: op = Iop_Avg16Ux4;   break;
5633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEE: op = Iop_Max16Sx4;   break;
5634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDE: op = Iop_Max8Ux8;    break;
5635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEA: op = Iop_Min16Sx4;   break;
5636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDA: op = Iop_Min8Ux8;    break;
5637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE4: op = Iop_MulHi16Ux4; break;
5638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
5639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Introduced in SSE2 */
5641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD4: op = Iop_Add64; break;
5642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFB: op = Iop_Sub64; break;
5643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
5645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("\n0x%x\n", (Int)opc);
5646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("dis_MMXop_regmem_to_reg");
5647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef XXX
5650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   argG = getMMXReg(gregOfRM(modrm));
5652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (invG)
5653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argG = unop(Iop_Not64, argG);
5654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isReg) {
5656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
5657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argE = getMMXReg(eregOfRM(modrm));
5658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
5659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    len;
5660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
5662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argE = loadLE(Ity_I64, mkexpr(addr));
5663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (eLeft) {
5666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argL = argE;
5667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argR = argG;
5668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
5669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argL = argG;
5670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argR = argE;
5671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op != Iop_INVALID) {
5674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(hName == NULL);
5675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(hAddr == NULL);
5676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(op, argL, argR));
5677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
5678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(hName != NULL);
5679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(hAddr != NULL);
5680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( res,
5681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              mkIRExprCCall(
5682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Ity_I64,
5683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 0/*regparms*/, hName, hAddr,
5684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkIRExprVec_2( argL, argR )
5685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
5686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
5687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putMMXReg( gregOfRM(modrm), mkexpr(res) );
5690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%s %s, %s\n",
5692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       name, show_granularity ? nameMMXGran(opc & 3) : "",
5693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameMMXReg(gregOfRM(modrm)) );
5695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
5697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vector by scalar shift of G by the amount specified at the bottom
5701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of E.  This is a straight copy of dis_SSE_shiftG_byE. */
5702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_MMX_shiftG_byE ( UChar sorb, Int delta,
5704436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 const HChar* opname, IROp op )
5705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
5707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen, size;
5708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
5709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    shl, shr, sar;
5710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getIByte(delta);
5711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  g0   = newTemp(Ity_I64);
5712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  g1   = newTemp(Ity_I64);
5713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  amt  = newTemp(Ity_I32);
5714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  amt8 = newTemp(Ity_I8);
5715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
5717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
5718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
5719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameMMXReg(eregOfRM(rm)),
5720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameMMXReg(gregOfRM(rm)) );
5721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
5722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
5723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
5724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
5725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
5726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
5727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameMMXReg(gregOfRM(rm)) );
5728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
5729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( g0,   getMMXReg(gregOfRM(rm)) );
5731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
5732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shl = shr = sar = False;
5734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   size = 0;
5735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
5736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN16x4: shl = True; size = 32; break;
5737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN32x2: shl = True; size = 32; break;
5738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shl64:    shl = True; size = 64; break;
5739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN16x4: shr = True; size = 16; break;
5740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN32x2: shr = True; size = 32; break;
5741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shr64:    shr = True; size = 64; break;
5742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN16x4: sar = True; size = 16; break;
5743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN32x2: sar = True; size = 32; break;
5744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
5745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shl || shr) {
5748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(
5749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        g1,
5750436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        IRExpr_ITE(
5751436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
5752436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           binop(op, mkexpr(g0), mkexpr(amt8)),
5753436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           mkU64(0)
5754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
5755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
5756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else
5757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sar) {
5758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(
5759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        g1,
5760436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        IRExpr_ITE(
5761436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
5762436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           binop(op, mkexpr(g0), mkexpr(amt8)),
5763436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           binop(op, mkexpr(g0), mkU8(size-1))
5764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
5765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
5766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
5767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
5768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0);
5769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putMMXReg( gregOfRM(rm), mkexpr(g1) );
5772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
5773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vector by scalar shift of E by an immediate byte.  This is a
5777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   straight copy of dis_SSE_shiftE_imm. */
5778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
5780436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovUInt dis_MMX_shiftE_imm ( Int delta, const HChar* opname, IROp op )
5781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    shl, shr, sar;
5783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getIByte(delta);
5784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  e0   = newTemp(Ity_I64);
5785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  e1   = newTemp(Ity_I64);
5786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   amt, size;
5787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(epartIsReg(rm));
5788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(gregOfRM(rm) == 2
5789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
5790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   amt = getIByte(delta+1);
5791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta += 2;
5792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s $%d,%s\n", opname,
5793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      (Int)amt,
5794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameMMXReg(eregOfRM(rm)) );
5795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( e0, getMMXReg(eregOfRM(rm)) );
5797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shl = shr = sar = False;
5799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   size = 0;
5800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
5801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN16x4: shl = True; size = 16; break;
5802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN32x2: shl = True; size = 32; break;
5803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shl64:    shl = True; size = 64; break;
5804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN16x4: sar = True; size = 16; break;
5805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN32x2: sar = True; size = 32; break;
5806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN16x4: shr = True; size = 16; break;
5807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN32x2: shr = True; size = 32; break;
5808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shr64:    shr = True; size = 64; break;
5809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
5810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shl || shr) {
5813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e1, amt >= size
5814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ? mkU64(0)
5815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : binop(op, mkexpr(e0), mkU8(amt))
5816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
5817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else
5818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sar) {
5819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e1, amt >= size
5820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ? binop(op, mkexpr(e0), mkU8(size-1))
5821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : binop(op, mkexpr(e0), mkU8(amt))
5822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
5823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
5824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
5825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0);
5826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putMMXReg( eregOfRM(rm), mkexpr(e1) );
5829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
5830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Completely handle all MMX instructions except emms. */
5834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
5836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, Int delta )
5837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   len;
5839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar modrm;
5840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
5841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar opc = getIByte(delta);
5842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta++;
5843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* dis_MMX handles all insns except emms. */
5845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_MMX_preamble();
5846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (opc) {
5848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6E:
5850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
5851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
5854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
5855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
5856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putMMXReg(
5857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               gregOfRM(modrm),
5858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop( Iop_32HLto64,
5859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(0),
5860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      getIReg(4, eregOfRM(modrm)) ) );
5861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movd %s, %s\n",
5862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
5864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += len;
5866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putMMXReg(
5867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               gregOfRM(modrm),
5868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop( Iop_32HLto64,
5869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(0),
5870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      loadLE(Ity_I32, mkexpr(addr)) ) );
5871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
5872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
5876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
5879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
5880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
5881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg( 4, eregOfRM(modrm),
5882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movd %s, %s\n",
5884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
5885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
5886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += len;
5888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(addr),
5889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
5891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6F:
5895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
5896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
5899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
5900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
5901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movq %s, %s\n",
5903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
5905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += len;
5907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movq %s, %s\n",
5909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                dis_buf, nameMMXReg(gregOfRM(modrm)));
5910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x7F:
5914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
5915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
5918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
5919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
5920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putMMXReg( eregOfRM(modrm), getMMXReg(gregOfRM(modrm)) );
5921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movq %s, %s\n",
5922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
5923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
5924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += len;
5926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
5927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("mov(nt)q %s, %s\n",
5928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameMMXReg(gregOfRM(modrm)), dis_buf);
5929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFC:
5933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFD:
5934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
5935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEC:
5941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
5942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDC:
5948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
5949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF8:
5955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF9:
5956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFA: /* PSUBgg (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, "psub", True );
5960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE8:
5963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
5964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD8:
5970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
5971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
5977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
5983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
5989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(sz == 4);
5990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
5991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
5992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x74:
5994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x75:
5995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
5996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
5997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
5998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
5999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x64:
6002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x65:
6003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
6004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
6007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
6010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
6013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
6016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
6019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
6022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
6025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x68:
6028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x69:
6029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
6030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
6033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x60:
6036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x61:
6037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
6038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
6041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
6044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
6047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
6050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
6053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
6056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
6059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
6062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
6065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SHIFT_BY_REG(_name,_op)                                 \
6068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
6069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                break;
6070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
6072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
6073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
6074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
6075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
6077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
6078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
6079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
6080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
6082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
6083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
6084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SHIFT_BY_REG
6086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x71:
6088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x72:
6089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x73: {
6090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
6091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar byte2, subopc;
6092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         byte2  = getIByte(delta);           /* amode / sub-opcode */
6095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         subopc = toUChar( (byte2 >> 3) & 7 );
6096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        define SHIFT_BY_IMM(_name,_op)                         \
6098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             do { delta = dis_MMX_shiftE_imm(delta,_name,_op);  \
6099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             } while (0)
6100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              if (subopc == 2 /*SRL*/ && opc == 0x71)
6102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
6103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 2 /*SRL*/ && opc == 0x72)
6104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
6105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 2 /*SRL*/ && opc == 0x73)
6106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psrlq", Iop_Shr64);
6107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 4 /*SAR*/ && opc == 0x71)
6109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
6110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 4 /*SAR*/ && opc == 0x72)
6111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
6112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 6 /*SHL*/ && opc == 0x71)
6114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
6115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 6 /*SHL*/ && opc == 0x72)
6116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
6117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 6 /*SHL*/ && opc == 0x73)
6118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psllq", Iop_Shl64);
6119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else goto mmx_decode_failure;
6121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        undef SHIFT_BY_IMM
6123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
6125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF7: {
6127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr    = newTemp(Ity_I32);
6128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp regD    = newTemp(Ity_I64);
6129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp regM    = newTemp(Ity_I64);
6130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp mask    = newTemp(Ity_I64);
6131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp olddata = newTemp(Ity_I64);
6132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp newdata = newTemp(Ity_I64);
6133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
6135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4 || (!epartIsReg(modrm)))
6136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
6138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
6140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( regM, getMMXReg( eregOfRM(modrm) ));
6141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( regD, getMMXReg( gregOfRM(modrm) ));
6142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( mask, binop(Iop_SarN8x8, mkexpr(regM), mkU8(7)) );
6143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( olddata, loadLE( Ity_I64, mkexpr(addr) ));
6144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( newdata,
6145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Or64,
6146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And64,
6147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(regD),
6148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(mask) ),
6149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And64,
6150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(olddata),
6151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_Not64, mkexpr(mask)))) );
6152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), mkexpr(newdata) );
6153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("maskmovq %s,%s\n", nameMMXReg( eregOfRM(modrm) ),
6154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameMMXReg( gregOfRM(modrm) ) );
6155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
6157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* --- MMX decode failure --- */
6159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
6160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mmx_decode_failure:
6161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *decode_ok = False;
6162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return delta; /* ignored */
6163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_ok = True;
6167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
6168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
6172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- More misc arithmetic and other obscure insns.        ---*/
6173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
6174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Double length left and right shifts.  Apparently only required in
6176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v-size (no b- variant). */
6177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_SHLRD_Gv_Ev ( UChar sorb,
6179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Int delta, UChar modrm,
6180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Int sz,
6181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr* shift_amt,
6182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Bool amt_is_literal,
6183436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       const HChar* shift_amt_txt,
6184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Bool left_shift )
6185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* shift_amt :: Ity_I8 is the amount to shift.  shift_amt_txt is used
6187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for printing it.   And eip on entry points at the modrm byte. */
6188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int len;
6189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
6190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty       = szToITy(sz);
6192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp gsrc     = newTemp(ty);
6193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp esrc     = newTemp(ty);
6194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp addr     = IRTemp_INVALID;
6195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpSH    = newTemp(Ity_I8);
6196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpL     = IRTemp_INVALID;
6197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpRes   = IRTemp_INVALID;
6198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpSubSh = IRTemp_INVALID;
6199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   mkpair;
6200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   getres;
6201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   shift;
6202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* mask = NULL;
6203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 2 || sz == 4);
6205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The E-part is the destination; this is shifted.  The G-part
6207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      supplies bits to be shifted into the E-part, but is not
6208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      changed.
6209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If shifting left, form a double-length word with E at the top
6211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      and G at the bottom, and shift this left.  The result is then in
6212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the high part.
6213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If shifting right, form a double-length word with G at the top
6215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      and E at the bottom, and shift this right.  The result is then
6216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      at the bottom.  */
6217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Fetch the operands. */
6219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
6221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
6223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
6224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( esrc, getIReg(sz, eregOfRM(modrm)) );
6225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sh%cd%c %s, %s, %s\n",
6226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ( left_shift ? 'l' : 'r' ), nameISize(sz),
6227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          shift_amt_txt,
6228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
6229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta, dis_buf );
6231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
6232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( esrc, loadLE(ty, mkexpr(addr)) );
6233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sh%cd%c %s, %s, %s\n",
6234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ( left_shift ? 'l' : 'r' ), nameISize(sz),
6235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          shift_amt_txt,
6236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameIReg(sz, gregOfRM(modrm)), dis_buf);
6237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Round up the relevant primops. */
6240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4) {
6242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpL     = newTemp(Ity_I64);
6243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpRes   = newTemp(Ity_I32);
6244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpSubSh = newTemp(Ity_I32);
6245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mkpair   = Iop_32HLto64;
6246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      getres   = left_shift ? Iop_64HIto32 : Iop_64to32;
6247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      shift    = left_shift ? Iop_Shl64 : Iop_Shr64;
6248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mask     = mkU8(31);
6249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* sz == 2 */
6251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpL     = newTemp(Ity_I32);
6252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpRes   = newTemp(Ity_I16);
6253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpSubSh = newTemp(Ity_I16);
6254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mkpair   = Iop_16HLto32;
6255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      getres   = left_shift ? Iop_32HIto16 : Iop_32to16;
6256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      shift    = left_shift ? Iop_Shl32 : Iop_Shr32;
6257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mask     = mkU8(15);
6258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Do the shift, calculate the subshift value, and set
6261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the flag thunk. */
6262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
6264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (left_shift)
6266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
6267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
6268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
6269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
6271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tmpSubSh,
6272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(getres,
6273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(shift,
6274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(tmpL),
6275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And8,
6276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mask))) );
6278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
6280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              tmpRes, tmpSubSh, ty, tmpSH );
6281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Put result back. */
6283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
6285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
6286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), mkexpr(tmpRes) );
6288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (amt_is_literal) delta++;
6291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
6292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle BT/BTS/BTR/BTC Gv, Ev.  Apparently b-size is not
6296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   required. */
6297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
6299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6300436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic const HChar* nameBtOp ( BtOp op )
6301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
6303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case BtOpNone:  return "";
6304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case BtOpSet:   return "s";
6305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case BtOpReset: return "r";
6306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case BtOpComp:  return "c";
6307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameBtOp(x86)");
6308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_bt_G_E ( VexAbiInfo* vbi,
6314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  UChar sorb, Bool locked, Int sz, Int delta, BtOp op )
6315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
6317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  modrm;
6318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    len;
6319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
6320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          t_addr1, t_esp, t_mask, t_new;
6321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 2 || sz == 4);
6323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_fetched = t_bitno0 = t_bitno1 = t_bitno2
6325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             = t_addr0 = t_addr1 = t_esp
6326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             = t_mask = t_new = IRTemp_INVALID;
6327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_fetched = newTemp(Ity_I8);
6329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_new     = newTemp(Ity_I8);
6330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_bitno0  = newTemp(Ity_I32);
6331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_bitno1  = newTemp(Ity_I32);
6332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_bitno2  = newTemp(Ity_I8);
6333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_addr1   = newTemp(Ity_I32);
6334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm     = getIByte(delta);
6335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t_bitno0, widenSto32(getIReg(sz, gregOfRM(modrm))) );
6337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
6339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
6340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Get it onto the client's stack. */
6341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_esp = newTemp(Ity_I32);
6342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_addr0 = newTemp(Ity_I32);
6343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* For the choice of the value 128, see comment in dis_bt_G_E in
6345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         guest_amd64_toIR.c.  We point out here only that 128 is
6346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         fast-cased in Memcheck and is > 0, so seems like a good
6347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         choice. */
6348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(vbi->guest_stack_redzone_size == 0);
6349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(128)) );
6350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, mkexpr(t_esp));
6351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
6353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Make t_addr0 point at it. */
6355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_addr0, mkexpr(t_esp) );
6356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Mask out upper bits of the shift amount, since we're doing a
6358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         reg. */
6359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_bitno1, binop(Iop_And32,
6360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(t_bitno0),
6361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(sz == 4 ? 31 : 15)) );
6362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
6365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
6366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_bitno1, mkexpr(t_bitno0) );
6367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* At this point: t_addr0 is the address being operated on.  If it
6370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      was a reg, we will have pushed it onto the client's stack.
6371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_bitno1 is the bit number, suitably masked in the case of a
6372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg.  */
6373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now the main sequence. */
6375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t_addr1,
6376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_Add32,
6377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkexpr(t_addr0),
6378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
6379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t_addr1 now holds effective address */
6381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t_bitno2,
6383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(Iop_32to8,
6384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
6385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t_bitno2 contains offset of bit within byte */
6387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op != BtOpNone) {
6389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_mask = newTemp(Ity_I8);
6390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
6391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t_mask is now a suitable byte mask */
6394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
6396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op != BtOpNone) {
6398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (op) {
6399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BtOpSet:
6400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t_new,
6401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Or8, mkexpr(t_fetched), mkexpr(t_mask)) );
6402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
6403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BtOpComp:
6404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t_new,
6405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Xor8, mkexpr(t_fetched), mkexpr(t_mask)) );
6406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
6407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BtOpReset:
6408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t_new,
6409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And8, mkexpr(t_fetched),
6410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_Not8, mkexpr(t_mask))) );
6411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
6412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
6413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("dis_bt_G_E(x86)");
6414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
6415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (locked && !epartIsReg(modrm)) {
6416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         casLE( mkexpr(t_addr1), mkexpr(t_fetched)/*expd*/,
6417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkexpr(t_new)/*new*/,
6418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 guest_EIP_curr_instr );
6419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
6420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(t_addr1), mkexpr(t_new) );
6421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
6422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Side effect done; now get selected bit into Carry flag */
6425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
6426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
6427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
6429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_CC_DEP1,
6430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And32,
6431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Shr32,
6432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_8Uto32, mkexpr(t_fetched)),
6433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(t_bitno2)),
6434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU32(1)))
6435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       );
6436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
6437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
6438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
6439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Move reg operand from stack back to reg */
6441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
6442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t_esp still points at it. */
6443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
6444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(128)) );
6445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("bt%s%c %s, %s\n",
6448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
6449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
6450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
6452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle BSF/BSR.  Only v-size seems necessary. */
6457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_bs_E_G ( UChar sorb, Int sz, Int delta, Bool fwds )
6459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   isReg;
6461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  modrm;
6462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
6463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty  = szToITy(sz);
6465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src = newTemp(ty);
6466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst = newTemp(ty);
6467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src32 = newTemp(Ity_I32);
6469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst32 = newTemp(Ity_I32);
6470436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   IRTemp srcB  = newTemp(Ity_I1);
6471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 4 || sz == 2);
6473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm = getIByte(delta);
6475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   isReg = epartIsReg(modrm);
6477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isReg) {
6478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
6479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, getIReg(sz, eregOfRM(modrm)) );
6480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    len;
6482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
6484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, loadLE(ty, mkexpr(addr)) );
6485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("bs%c%c %s, %s\n",
6488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       fwds ? 'f' : 'r', nameISize(sz),
6489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
6490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameIReg(sz, gregOfRM(modrm)));
6491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6492436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Generate a bool expression which is zero iff the original is
6493436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      zero, and nonzero otherwise.  Ask for a CmpNE version which, if
6494436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      instrumented by Memcheck, is instrumented expensively, since
6495436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      this may be used on the output of a preceding movmskb insn,
6496436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      which has been known to be partially defined, and in need of
6497436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      careful handling. */
6498436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   assign( srcB, binop(mkSizedOp(ty,Iop_ExpCmpNE8),
6499436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       mkexpr(src), mkU(ty,0)) );
6500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Flags: Z is 1 iff source value is zero.  All others
6502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      are undefined -- we force them to zero. */
6503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
6504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
6506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_CC_DEP1,
6507436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            IRExpr_ITE( mkexpr(srcB),
6508436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        /* src!=0 */
6509436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        mkU32(0),
6510436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        /* src==0 */
6511436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        mkU32(X86G_CC_MASK_Z)
6512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        )
6513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ));
6514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
6515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
6516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
6517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Result: iff source value is zero, we can't use
6519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
6520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      But anyway, Intel x86 semantics say the result is undefined in
6521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      such situations.  Hence handle the zero case specially. */
6522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Bleh.  What we compute:
6524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsf32:  if src == 0 then 0 else  Ctz32(src)
6526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsr32:  if src == 0 then 0 else  31 - Clz32(src)
6527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsf16:  if src == 0 then 0 else  Ctz32(16Uto32(src))
6529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsr16:  if src == 0 then 0 else  31 - Clz32(16Uto32(src))
6530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      First, widen src to 32 bits if it is not already.
6532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
6534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dst register unchanged when src == 0.  Hence change accordingly.
6535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
6536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2)
6537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
6538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
6539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src32, mkexpr(src) );
6540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The main computation, guarding against zero. */
6542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( dst32,
6543436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           IRExpr_ITE(
6544436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov              mkexpr(srcB),
6545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              /* src != 0 */
6546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              fwds ? unop(Iop_Ctz32, mkexpr(src32))
6547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   : binop(Iop_Sub32,
6548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32(31),
6549436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                           unop(Iop_Clz32, mkexpr(src32))),
6550436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov              /* src == 0 -- leave dst unchanged */
6551436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov              widenUto32( getIReg( sz, gregOfRM(modrm) ) )
6552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           )
6553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
6554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2)
6556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
6557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
6558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst, mkexpr(dst32) );
6559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* dump result back */
6561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
6562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
6564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid codegen_xchg_eAX_Reg ( Int sz, Int reg )
6569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
6571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1 = newTemp(ty);
6572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2 = newTemp(ty);
6573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 2 || sz == 4);
6574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t1, getIReg(sz, R_EAX) );
6575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t2, getIReg(sz, reg) );
6576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( sz, R_EAX, mkexpr(t2) );
6577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg( sz, reg, mkexpr(t1) );
6578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("xchg%c %s, %s\n",
6579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
6580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid codegen_SAHF ( void )
6585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set the flags to:
6587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (x86g_calculate_flags_all() & X86G_CC_MASK_O)  -- retain the old O flag
6588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                |X86G_CC_MASK_P|X86G_CC_MASK_C)
6590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
6591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       |X86G_CC_MASK_C|X86G_CC_MASK_P;
6593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp oldflags   = newTemp(Ity_I32);
6594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldflags, mk_x86g_calculate_eflags_all() );
6595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
6596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
6597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1,
6599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_Or32,
6600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
6601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_And32,
6602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
6603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU32(mask_SZACP))
6604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
6605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ));
6606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
6607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
6608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
6609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid codegen_LAHF ( void  )
6614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* AH <- EFLAGS(SF:ZF:0:AF:0:PF:1:CF) */
6616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* eax_with_hole;
6617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* new_byte;
6618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* new_eax;
6619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt    mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        |X86G_CC_MASK_C|X86G_CC_MASK_P;
6621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  flags = newTemp(Ity_I32);
6623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( flags, mk_x86g_calculate_eflags_all() );
6624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   eax_with_hole
6626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = binop(Iop_And32, getIReg(4, R_EAX), mkU32(0xFFFF00FF));
6627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   new_byte
6628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = binop(Iop_Or32, binop(Iop_And32, mkexpr(flags), mkU32(mask_SZACP)),
6629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32(1<<1));
6630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   new_eax
6631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = binop(Iop_Or32, eax_with_hole,
6632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl32, new_byte, mkU8(8)));
6633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(4, R_EAX, new_eax);
6634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_cmpxchg_G_E ( UChar       sorb,
6639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Bool        locked,
6640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Int         size,
6641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Int         delta0 )
6642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
6644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   len;
6645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty    = szToITy(size);
6647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp acc   = newTemp(ty);
6648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src   = newTemp(ty);
6649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dest  = newTemp(ty);
6650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dest2 = newTemp(ty);
6651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp acc2  = newTemp(ty);
6652436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   IRTemp cond  = newTemp(Ity_I1);
6653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp addr  = IRTemp_INVALID;
6654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  rm    = getUChar(delta0);
6655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* There are 3 cases to consider:
6657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-reg: ignore any lock prefix, generate sequence based
6659436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               on ITE
6660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-mem, not locked: ignore any lock prefix, generate sequence
6662436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                           based on ITE
6663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-mem, locked: use IRCAS
6665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
6666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 1 */
6668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dest, getIReg(size, eregOfRM(rm)) );
6669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta0++;
6670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, getIReg(size, gregOfRM(rm)) );
6671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc, getIReg(size, R_EAX) );
6672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6673436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( cond, mk_x86g_calculate_condition(X86CondZ) );
6674436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( dest2, IRExpr_ITE(mkexpr(cond), mkexpr(src), mkexpr(dest)) );
6675436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( acc2,  IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
6676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, R_EAX, mkexpr(acc2));
6677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, eregOfRM(rm), mkexpr(dest2));
6678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmpxchg%c %s,%s\n", nameISize(size),
6679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(size,gregOfRM(rm)),
6680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(size,eregOfRM(rm)) );
6681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (!epartIsReg(rm) && !locked) {
6683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 2 */
6684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta0, dis_buf );
6685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dest, loadLE(ty, mkexpr(addr)) );
6686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta0 += len;
6687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, getIReg(size, gregOfRM(rm)) );
6688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc, getIReg(size, R_EAX) );
6689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6690436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( cond, mk_x86g_calculate_condition(X86CondZ) );
6691436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( dest2, IRExpr_ITE(mkexpr(cond), mkexpr(src), mkexpr(dest)) );
6692436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( acc2,  IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
6693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, R_EAX, mkexpr(acc2));
6694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), mkexpr(dest2) );
6695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmpxchg%c %s,%s\n", nameISize(size),
6696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(size,gregOfRM(rm)), dis_buf);
6697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (!epartIsReg(rm) && locked) {
6699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 3 */
6700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* src is new value.  acc is expected value.  dest is old value.
6701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Compute success from the output of the IRCAS, and steer the
6702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         new value for EAX accordingly: in case of success, EAX is
6703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unchanged. */
6704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta0, dis_buf );
6705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta0 += len;
6706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, getIReg(size, gregOfRM(rm)) );
6707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc, getIReg(size, R_EAX) );
6708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_CAS(
6709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkIRCAS( IRTemp_INVALID, dest, Iend_LE, mkexpr(addr),
6710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  NULL, mkexpr(acc), NULL, mkexpr(src) )
6711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ));
6712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6713436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( cond, mk_x86g_calculate_condition(X86CondZ) );
6714436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( acc2,  IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
6715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(size, R_EAX, mkexpr(acc2));
6716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmpxchg%c %s,%s\n", nameISize(size),
6717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(size,gregOfRM(rm)), dis_buf);
6718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else vassert(0);
6720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta0;
6722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle conditional move instructions of the form
6726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cmovcc E(reg-or-mem), G(reg)
6727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(src) is reg-or-mem
6729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(dst) is reg.
6730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %E, tmps
6732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       GET %G, tmpd
6733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       CMOVcc tmps, tmpd
6734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpd, %G
6735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem  -->    (getAddr E) -> tmpa
6737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmps
6738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       GET %G, tmpd
6739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       CMOVcc tmps, tmpd
6740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpd, %G
6741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
6742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_cmov_E_G ( UChar       sorb,
6744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int         sz,
6745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    X86Condcode cond,
6746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int         delta0 )
6747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm  = getIByte(delta0);
6749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
6750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   len;
6751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty   = szToITy(sz);
6753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmps = newTemp(ty);
6754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpd = newTemp(ty);
6755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmps, getIReg(sz, eregOfRM(rm)) );
6758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(rm),
6761436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  IRExpr_ITE( mk_x86g_calculate_condition(cond),
6762436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                              mkexpr(tmps),
6763436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                              mkexpr(tmpd) )
6764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             );
6765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmov%c%s %s,%s\n", nameISize(sz),
6766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              name_X86Condcode(cond),
6767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameIReg(sz,eregOfRM(rm)),
6768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameIReg(sz,gregOfRM(rm)));
6769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
6770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
6773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
6774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmps, loadLE(ty, mkexpr(addr)) );
6776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(rm),
6779436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  IRExpr_ITE( mk_x86g_calculate_condition(cond),
6780436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                              mkexpr(tmps),
6781436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                              mkexpr(tmpd) )
6782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             );
6783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmov%c%s %s,%s\n", nameISize(sz),
6785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              name_X86Condcode(cond),
6786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              dis_buf,
6787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameIReg(sz,gregOfRM(rm)));
6788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
6789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_xadd_G_E ( UChar sorb, Bool locked, Int sz, Int delta0,
6795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool* decodeOK )
6796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   len;
6798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm = getIByte(delta0);
6799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
6800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty    = szToITy(sz);
6802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpd  = newTemp(ty);
6803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpt0 = newTemp(ty);
6804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpt1 = newTemp(ty);
6805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* There are 3 cases to consider:
6807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-reg: ignore any lock prefix,
6809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               generate 'naive' (non-atomic) sequence
6810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-mem, not locked: ignore any lock prefix, generate 'naive'
6812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (non-atomic) sequence
6813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-mem, locked: use IRCAS
6815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
6816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 1 */
6819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd,  getIReg(sz, eregOfRM(rm)));
6820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(tmpd), mkexpr(tmpt0)) );
6823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, eregOfRM(rm), mkexpr(tmpt1));
6825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("xadd%c %s, %s\n",
6827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameISize(sz), nameIReg(sz,gregOfRM(rm)),
6828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          				 nameIReg(sz,eregOfRM(rm)));
6829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decodeOK = True;
6830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
6831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (!epartIsReg(rm) && !locked) {
6833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 2 */
6834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd,  loadLE(ty, mkexpr(addr)) );
6836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(tmpd), mkexpr(tmpt0)) );
6839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), mkexpr(tmpt1) );
6840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("xadd%c %s, %s\n",
6843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decodeOK = True;
6845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
6846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (!epartIsReg(rm) && locked) {
6848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 3 */
6849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd,  loadLE(ty, mkexpr(addr)) );
6851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(tmpd), mkexpr(tmpt0)) );
6854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      casLE( mkexpr(addr), mkexpr(tmpd)/*expVal*/,
6855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(tmpt1)/*newVal*/, guest_EIP_curr_instr );
6856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("xadd%c %s, %s\n",
6859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decodeOK = True;
6861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
6862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*UNREACHED*/
6864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(0);
6865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
6868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_mov_Ew_Sw ( UChar sorb, Int delta0 )
6871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    len;
6873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp addr;
6874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  rm  = getIByte(delta0);
6875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
6876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
6879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
6880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
6881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta0, dis_buf );
6883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
6884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
6885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
6886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Move 16 bits from G (a segment register) to Ew (ireg or mem).  If
6890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dst is ireg and sz==4, zero out top half of it.  */
6891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_mov_Sw_Ew ( UChar sorb,
6894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Int   sz,
6895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Int   delta0 )
6896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    len;
6898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp addr;
6899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  rm  = getIByte(delta0);
6900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
6901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 2 || sz == 4);
6903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4)
6906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
6908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
6912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, sorb, delta0, dis_buf );
6914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
6915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
6916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
6917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_push_segreg ( UInt sreg, Int sz )
6923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    IRTemp t1 = newTemp(Ity_I16);
6925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    IRTemp ta = newTemp(Ity_I32);
6926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    vassert(sz == 2 || sz == 4);
6927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assign( t1, getSReg(sreg) );
6929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    putIReg(4, R_ESP, mkexpr(ta));
6931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    storeLE( mkexpr(ta), mkexpr(t1) );
6932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    DIP("push%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
6934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_pop_segreg ( UInt sreg, Int sz )
6938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    IRTemp t1 = newTemp(Ity_I16);
6940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    IRTemp ta = newTemp(Ity_I32);
6941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    vassert(sz == 2 || sz == 4);
6942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assign( ta, getIReg(4, R_ESP) );
6944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
6945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
6947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    putSReg( sreg, mkexpr(t1) );
6948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    DIP("pop%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
6949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6952663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengvoid dis_ret ( /*MOD*/DisResult* dres, UInt d32 )
6953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6954663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   IRTemp t1 = newTemp(Ity_I32);
6955663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   IRTemp t2 = newTemp(Ity_I32);
6956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(t1, getIReg(4,R_ESP));
6957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
6959663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   jmp_treg(dres, Ijk_Ret, t2);
6960663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres->whatNext == Dis_StopHere);
6961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
6964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- SSE/SSE2/SSE3 helpers                                ---*/
6965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
6966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6967436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Indicates whether the op requires a rounding-mode argument.  Note
6968436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   that this covers only vector floating point arithmetic ops, and
6969436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   omits the scalar ones that need rounding modes.  Note also that
6970436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   inconsistencies here will get picked up later by the IR sanity
6971436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   checker, so this isn't correctness-critical. */
6972436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool requiresRMode ( IROp op )
6973436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
6974436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   switch (op) {
6975436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* 128 bit ops */
6976436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case Iop_Add32Fx4: case Iop_Sub32Fx4:
6977436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case Iop_Mul32Fx4: case Iop_Div32Fx4:
6978436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case Iop_Add64Fx2: case Iop_Sub64Fx2:
6979436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case Iop_Mul64Fx2: case Iop_Div64Fx2:
6980436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         return True;
6981436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      default:
6982436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
6983436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
6984436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return False;
6985436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
6986436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
6987436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
6988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Worker function; do not call directly.
6989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Handles full width G = G `op` E   and   G = (not G) `op` E.
6990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
6991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_E_to_G_all_wrk (
6993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UChar sorb, Int delta,
6994436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               const HChar* opname, IROp op,
6995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Bool   invertG
6996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
6997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
6999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
7000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
7002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* gpart
7003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRM(rm)))
7004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                : getXMMReg(gregOfRM(rm));
7005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7006436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      putXMMReg(
7007436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         gregOfRM(rm),
7008436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         requiresRMode(op)
7009436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            ? triop(op, get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
7010436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        gpart,
7011436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        getXMMReg(eregOfRM(rm)))
7012436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            : binop(op, gpart,
7013436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        getXMMReg(eregOfRM(rm)))
7014436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      );
7015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
7017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
7019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
7021436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      putXMMReg(
7022436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         gregOfRM(rm),
7023436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         requiresRMode(op)
7024436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            ? triop(op, get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
7025436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        gpart,
7026436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        loadLE(Ity_V128, mkexpr(addr)))
7027436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            : binop(op, gpart,
7028436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                        loadLE(Ity_V128, mkexpr(addr)))
7029436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      );
7030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
7032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
7034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* All lanes SSE binary operation, G = G `op` E. */
7039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7041436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovUInt dis_SSE_E_to_G_all ( UChar sorb, Int delta, const HChar* opname, IROp op )
7042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
7044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* All lanes SSE binary operation, G = (not G) `op` E. */
7047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt dis_SSE_E_to_G_all_invG ( UChar sorb, Int delta,
7050436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                               const HChar* opname, IROp op )
7051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
7053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
7057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_E_to_G_lo32 ( UChar sorb, Int delta,
7059436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                  const HChar* opname, IROp op )
7060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
7062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
7063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
7065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* gpart = getXMMReg(gregOfRM(rm));
7066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
7068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart,
7069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getXMMReg(eregOfRM(rm))) );
7070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
7072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
7074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We can only do a 32-bit memory read, so the upper 3/4 of the
7076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         E operand needs to be made simply of zeroes. */
7077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp epart = newTemp(Ity_V128);
7078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
7079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( epart, unop( Iop_32UtoV128,
7080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           loadLE(Ity_I32, mkexpr(addr))) );
7081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
7082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart, mkexpr(epart)) );
7083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
7085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
7087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
7092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_E_to_G_lo64 ( UChar sorb, Int delta,
7094436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                  const HChar* opname, IROp op )
7095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
7097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
7098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
7100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* gpart = getXMMReg(gregOfRM(rm));
7101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
7103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart,
7104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getXMMReg(eregOfRM(rm))) );
7105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
7107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
7109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We can only do a 64-bit memory read, so the upper half of the
7111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         E operand needs to be made simply of zeroes. */
7112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp epart = newTemp(Ity_V128);
7113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
7114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( epart, unop( Iop_64UtoV128,
7115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           loadLE(Ity_I64, mkexpr(addr))) );
7116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
7117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart, mkexpr(epart)) );
7118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
7120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
7122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* All lanes unary SSE operation, G = op(E). */
7127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_E_to_G_unary_all (
7129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UChar sorb, Int delta,
7130436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               const HChar* opname, IROp op
7131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
7132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
7134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
7135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
7137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
7139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop(op, getXMMReg(eregOfRM(rm))) );
7140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
7142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
7144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
7146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
7147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
7148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
7150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
7152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
7157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_E_to_G_unary_lo32 (
7159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UChar sorb, Int delta,
7160436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               const HChar* opname, IROp op
7161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
7162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First we need to get the old G value and patch the low 32 bits
7164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of the E operand into it.  Then apply op and write back to G. */
7165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
7166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
7167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
7169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldG0 = newTemp(Ity_V128);
7170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldG1 = newTemp(Ity_V128);
7171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldG0, getXMMReg(gregOfRM(rm)) );
7173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldG1,
7176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop( Iop_SetV128lo32,
7177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(oldG0),
7178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     getXMMRegLane32(eregOfRM(rm), 0)) );
7179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
7182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
7184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
7186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldG1,
7187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop( Iop_SetV128lo32,
7188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(oldG0),
7189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     loadLE(Ity_I32, mkexpr(addr)) ));
7190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
7193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
7195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_E_to_G_unary_lo64 (
7202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UChar sorb, Int delta,
7203436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               const HChar* opname, IROp op
7204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
7205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First we need to get the old G value and patch the low 64 bits
7207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of the E operand into it.  Then apply op and write back to G. */
7208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
7209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
7210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
7212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldG0 = newTemp(Ity_V128);
7213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldG1 = newTemp(Ity_V128);
7214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldG0, getXMMReg(gregOfRM(rm)) );
7216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldG1,
7219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop( Iop_SetV128lo64,
7220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(oldG0),
7221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     getXMMRegLane64(eregOfRM(rm), 0)) );
7222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
7225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
7227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
7229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldG1,
7230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop( Iop_SetV128lo64,
7231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(oldG0),
7232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     loadLE(Ity_I64, mkexpr(addr)) ));
7233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
7236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
7238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* SSE integer binary operation:
7243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G = G `op` E   (eLeft == False)
7244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G = E `op` G   (eLeft == True)
7245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
7246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSEint_E_to_G(
7247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UChar sorb, Int delta,
7248436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               const HChar* opname, IROp op,
7249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Bool   eLeft
7250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
7251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
7253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
7254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getIByte(delta);
7256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* gpart = getXMMReg(gregOfRM(rm));
7257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* epart = NULL;
7258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      epart = getXMMReg(eregOfRM(rm));
7260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
7262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 1;
7264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr  = disAMode ( &alen, sorb, delta, dis_buf );
7266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      epart = loadLE(Ity_V128, mkexpr(addr));
7267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
7269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
7271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putXMMReg( gregOfRM(rm),
7273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              eLeft ? binop(op, epart, gpart)
7274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	            : binop(op, gpart, epart) );
7275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
7276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for doing SSE FP comparisons. */
7280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void findSSECmpOp ( Bool* needNot, IROp* op,
7282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Int imm8, Bool all_lanes, Int sz )
7283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   imm8 &= 7;
7285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *needNot = False;
7286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *op      = Iop_INVALID;
7287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (imm8 >= 4) {
7288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *needNot = True;
7289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm8 -= 4;
7290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && all_lanes) {
7293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm8) {
7294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: *op = Iop_CmpEQ32Fx4; return;
7295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: *op = Iop_CmpLT32Fx4; return;
7296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: *op = Iop_CmpLE32Fx4; return;
7297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: *op = Iop_CmpUN32Fx4; return;
7298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: break;
7299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && !all_lanes) {
7302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm8) {
7303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: *op = Iop_CmpEQ32F0x4; return;
7304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: *op = Iop_CmpLT32F0x4; return;
7305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: *op = Iop_CmpLE32F0x4; return;
7306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: *op = Iop_CmpUN32F0x4; return;
7307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: break;
7308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 8 && all_lanes) {
7311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm8) {
7312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: *op = Iop_CmpEQ64Fx2; return;
7313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: *op = Iop_CmpLT64Fx2; return;
7314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: *op = Iop_CmpLE64Fx2; return;
7315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: *op = Iop_CmpUN64Fx2; return;
7316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: break;
7317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 8 && !all_lanes) {
7320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm8) {
7321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: *op = Iop_CmpEQ64F0x2; return;
7322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: *op = Iop_CmpLT64F0x2; return;
7323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: *op = Iop_CmpLE64F0x2; return;
7324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: *op = Iop_CmpUN64F0x2; return;
7325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: break;
7326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("findSSECmpOp(x86,guest)");
7329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handles SSE 32F/64F comparisons. */
7332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSEcmp_E_to_G ( UChar sorb, Int delta,
7334436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov				const HChar* opname, Bool all_lanes, Int sz )
7335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
7337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen, imm8;
7338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    needNot = False;
7340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    op      = Iop_INVALID;
7341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  plain   = newTemp(Ity_V128);
7342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm      = getIByte(delta);
7343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UShort  mask    = 0;
7344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 4 || sz == 8);
7345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm8 = getIByte(delta+1);
7347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
7349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               getXMMReg(eregOfRM(rm))) );
7350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2;
7351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s $%d,%s,%s\n", opname,
7352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            (Int)imm8,
7353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameXMMReg(eregOfRM(rm)),
7354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameXMMReg(gregOfRM(rm)) );
7355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
7357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm8 = getIByte(delta+alen);
7358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( plain,
7360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(
7361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 op,
7362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 getXMMReg(gregOfRM(rm)),
7363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   all_lanes  ? loadLE(Ity_V128, mkexpr(addr))
7364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 : sz == 8    ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
7365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 : /*sz==4*/    unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
7366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             )
7367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
7368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen+1;
7369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s $%d,%s,%s\n", opname,
7370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            (Int)imm8,
7371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            dis_buf,
7372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameXMMReg(gregOfRM(rm)) );
7373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (needNot && all_lanes) {
7376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
7377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop(Iop_NotV128, mkexpr(plain)) );
7378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
7380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (needNot && !all_lanes) {
7381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mask = toUShort( sz==4 ? 0x000F : 0x00FF );
7382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm),
7383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
7384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else {
7386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(rm), mkexpr(plain) );
7387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
7390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vector by scalar shift of G by the amount specified at the bottom
7394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of E. */
7395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt dis_SSE_shiftG_byE ( UChar sorb, Int delta,
7397436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 const HChar* opname, IROp op )
7398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
7400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen, size;
7401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
7402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    shl, shr, sar;
7403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getIByte(delta);
7404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  g0   = newTemp(Ity_V128);
7405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  g1   = newTemp(Ity_V128);
7406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  amt  = newTemp(Ity_I32);
7407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  amt8 = newTemp(Ity_I8);
7408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
7410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRM(rm)),
7412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
7414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta, dis_buf );
7416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
7417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
7418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
7419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRM(rm)) );
7420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
7421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( g0,   getXMMReg(gregOfRM(rm)) );
7423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
7424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shl = shr = sar = False;
7426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   size = 0;
7427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
7428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN16x8: shl = True; size = 32; break;
7429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN32x4: shl = True; size = 32; break;
7430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN64x2: shl = True; size = 64; break;
7431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN16x8: sar = True; size = 16; break;
7432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN32x4: sar = True; size = 32; break;
7433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN16x8: shr = True; size = 16; break;
7434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN32x4: shr = True; size = 32; break;
7435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN64x2: shr = True; size = 64; break;
7436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
7437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shl || shr) {
7440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(
7441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        g1,
7442436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        IRExpr_ITE(
7443436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
7444436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           binop(op, mkexpr(g0), mkexpr(amt8)),
7445436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           mkV128(0x0000)
7446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
7447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
7448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else
7449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sar) {
7450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(
7451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        g1,
7452436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        IRExpr_ITE(
7453436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
7454436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           binop(op, mkexpr(g0), mkexpr(amt8)),
7455436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           binop(op, mkexpr(g0), mkU8(size-1))
7456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
7457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
7458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
7460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0);
7461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putXMMReg( gregOfRM(rm), mkexpr(g1) );
7464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
7465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vector by scalar shift of E by an immediate byte. */
7469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7471436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovUInt dis_SSE_shiftE_imm ( Int delta, const HChar* opname, IROp op )
7472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    shl, shr, sar;
7474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getIByte(delta);
7475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  e0   = newTemp(Ity_V128);
7476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  e1   = newTemp(Ity_V128);
7477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   amt, size;
7478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(epartIsReg(rm));
7479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(gregOfRM(rm) == 2
7480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
7481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   amt = getIByte(delta+1);
7482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta += 2;
7483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s $%d,%s\n", opname,
7484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      (Int)amt,
7485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameXMMReg(eregOfRM(rm)) );
7486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( e0, getXMMReg(eregOfRM(rm)) );
7487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shl = shr = sar = False;
7489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   size = 0;
7490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
7491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN16x8: shl = True; size = 16; break;
7492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN32x4: shl = True; size = 32; break;
7493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN64x2: shl = True; size = 64; break;
7494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN16x8: sar = True; size = 16; break;
7495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN32x4: sar = True; size = 32; break;
7496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN16x8: shr = True; size = 16; break;
7497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN32x4: shr = True; size = 32; break;
7498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN64x2: shr = True; size = 64; break;
7499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
7500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shl || shr) {
7503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e1, amt >= size
7504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ? mkV128(0x0000)
7505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : binop(op, mkexpr(e0), mkU8(amt))
7506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
7507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else
7508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sar) {
7509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e1, amt >= size
7510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ? binop(op, mkexpr(e0), mkU8(size-1))
7511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : binop(op, mkexpr(e0), mkU8(amt))
7512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
7513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
7515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0);
7516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putXMMReg( eregOfRM(rm), mkexpr(e1) );
7519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
7520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get the current SSE rounding mode. */
7524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
7526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return binop( Iop_And32,
7528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
7529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU32(3) );
7530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_sse_roundingmode ( IRExpr* sseround )
7533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, sseround) == Ity_I32);
7535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
7536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Break a 128-bit value up into four 32-bit ints. */
7539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void breakup128to32s ( IRTemp t128,
7541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			      /*OUTs*/
7542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              IRTemp* t3, IRTemp* t2,
7543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              IRTemp* t1, IRTemp* t0 )
7544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp hi64 = newTemp(Ity_I64);
7546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp lo64 = newTemp(Ity_I64);
7547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
7548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( lo64, unop(Iop_V128to64,   mkexpr(t128)) );
7549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t0 && *t0 == IRTemp_INVALID);
7551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t1 && *t1 == IRTemp_INVALID);
7552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t2 && *t2 == IRTemp_INVALID);
7553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t3 && *t3 == IRTemp_INVALID);
7554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t0 = newTemp(Ity_I32);
7556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t1 = newTemp(Ity_I32);
7557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t2 = newTemp(Ity_I32);
7558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t3 = newTemp(Ity_I32);
7559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t0, unop(Iop_64to32,   mkexpr(lo64)) );
7560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
7561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t2, unop(Iop_64to32,   mkexpr(hi64)) );
7562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
7563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Construct a 128-bit value from four 32-bit ints. */
7566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
7568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              IRTemp t1, IRTemp t0 )
7569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop( Iop_64HLtoV128,
7572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
7573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
7574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
7575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Break a 64-bit value up into four 16-bit ints. */
7578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void breakup64to16s ( IRTemp t64,
7580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             /*OUTs*/
7581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp* t3, IRTemp* t2,
7582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp* t1, IRTemp* t0 )
7583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp hi32 = newTemp(Ity_I32);
7585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp lo32 = newTemp(Ity_I32);
7586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
7587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( lo32, unop(Iop_64to32,   mkexpr(t64)) );
7588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t0 && *t0 == IRTemp_INVALID);
7590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t1 && *t1 == IRTemp_INVALID);
7591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t2 && *t2 == IRTemp_INVALID);
7592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t3 && *t3 == IRTemp_INVALID);
7593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t0 = newTemp(Ity_I16);
7595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t1 = newTemp(Ity_I16);
7596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t2 = newTemp(Ity_I16);
7597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t3 = newTemp(Ity_I16);
7598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t0, unop(Iop_32to16,   mkexpr(lo32)) );
7599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
7600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t2, unop(Iop_32to16,   mkexpr(hi32)) );
7601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
7602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Construct a 64-bit value from four 16-bit ints. */
7605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
7607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp t1, IRTemp t0 )
7608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop( Iop_32HLto64,
7611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
7614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate IR to set the guest %EFLAGS from the pushfl-format image
7617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in the given 32-bit temporary.  The flags that are set are: O S Z A
7618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   C P D ID AC.
7619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   In all cases, code to set AC is generated.  However, VEX actually
7621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ignores the AC value and so can optionally emit an emulation
7622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   warning when it is enabled.  In this routine, an emulation warning
7623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is only emitted if emit_AC_emwarn is True, in which case
7624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   next_insn_EIP must be correct (this allows for correct code
7625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   generation for popfl/popfw).  If emit_AC_emwarn is False,
7626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   next_insn_EIP is unimportant (this allows for easy if kludgey code
7627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   generation for IRET.) */
7628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid set_EFLAGS_from_value ( IRTemp t1,
7631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             Bool   emit_AC_emwarn,
7632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             Addr32 next_insn_EIP )
7633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRTemp(irsb->tyenv,t1) == Ity_I32);
7635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t1 is the flag word.  Mask out everything except OSZACP and set
7637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the flags thunk to X86G_CC_OP_COPY. */
7638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
7639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1,
7641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_And32,
7642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(t1),
7643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
7644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  | X86G_CC_MASK_A | X86G_CC_MASK_Z
7645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  | X86G_CC_MASK_S| X86G_CC_MASK_O )
7646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          )
7647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    )
7648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       );
7649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
7650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
7651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
7652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Also need to set the D flag, which is held in bit 10 of t1.
7654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
7655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
7656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_DFLAG,
7657436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            IRExpr_ITE(
7658436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               unop(Iop_32to1,
7659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And32,
7660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
7661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(1))),
7662436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               mkU32(0xFFFFFFFF),
7663436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               mkU32(1)))
7664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       );
7665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set the ID flag */
7667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
7668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_IDFLAG,
7669436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            IRExpr_ITE(
7670436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               unop(Iop_32to1,
7671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And32,
7672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
7673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(1))),
7674436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               mkU32(1),
7675436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               mkU32(0)))
7676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       );
7677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* And set the AC flag.  If setting it 1 to, possibly emit an
7679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      emulation warning. */
7680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
7681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_ACFLAG,
7682436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            IRExpr_ITE(
7683436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               unop(Iop_32to1,
7684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And32,
7685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shr32, mkexpr(t1), mkU8(18)),
7686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(1))),
7687436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               mkU32(1),
7688436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               mkU32(0)))
7689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       );
7690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (emit_AC_emwarn) {
7692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_emwarn( mkU32(EmWarn_X86_acFlag) );
7693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt(
7694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRStmt_Exit(
7695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( Iop_CmpNE32,
7696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_And32, mkexpr(t1), mkU32(1<<18)),
7697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mkU32(0) ),
7698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Ijk_EmWarn,
7699663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            IRConst_U32( next_insn_EIP ),
7700663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            OFFB_EIP
7701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
7702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
7703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for the SSSE3 (not SSE3) PMULHRSW insns.  Given two 64-bit
7708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   values (aa,bb), computes, for each of the 4 16-bit lanes:
7709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (((aa_lane *s32 bb_lane) >>u 14) + 1) >>u 1
7711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
7712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* dis_PMULHRSW_helper ( IRExpr* aax, IRExpr* bbx )
7713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aa      = newTemp(Ity_I64);
7715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bb      = newTemp(Ity_I64);
7716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aahi32s = newTemp(Ity_I64);
7717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aalo32s = newTemp(Ity_I64);
7718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bbhi32s = newTemp(Ity_I64);
7719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bblo32s = newTemp(Ity_I64);
7720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp rHi     = newTemp(Ity_I64);
7721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp rLo     = newTemp(Ity_I64);
7722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp one32x2 = newTemp(Ity_I64);
7723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(aa, aax);
7724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(bb, bbx);
7725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aahi32s,
7726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_SarN32x2,
7727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_InterleaveHI16x4, mkexpr(aa), mkexpr(aa)),
7728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU8(16) ));
7729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aalo32s,
7730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_SarN32x2,
7731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_InterleaveLO16x4, mkexpr(aa), mkexpr(aa)),
7732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU8(16) ));
7733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( bbhi32s,
7734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_SarN32x2,
7735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_InterleaveHI16x4, mkexpr(bb), mkexpr(bb)),
7736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU8(16) ));
7737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( bblo32s,
7738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_SarN32x2,
7739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_InterleaveLO16x4, mkexpr(bb), mkexpr(bb)),
7740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU8(16) ));
7741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(one32x2, mkU64( (1ULL << 32) + 1 ));
7742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
7743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      rHi,
7744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(
7745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Iop_ShrN32x2,
7746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
7747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_Add32x2,
7748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(
7749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Iop_ShrN32x2,
7750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul32x2, mkexpr(aahi32s), mkexpr(bbhi32s)),
7751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(14)
7752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
7753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkexpr(one32x2)
7754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ),
7755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkU8(1)
7756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
7757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
7758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
7759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      rLo,
7760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(
7761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Iop_ShrN32x2,
7762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
7763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_Add32x2,
7764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(
7765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Iop_ShrN32x2,
7766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul32x2, mkexpr(aalo32s), mkexpr(bblo32s)),
7767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(14)
7768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
7769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkexpr(one32x2)
7770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ),
7771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkU8(1)
7772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
7773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
7774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_CatEvenLanes16x4, mkexpr(rHi), mkexpr(rLo));
7776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for the SSSE3 (not SSE3) PSIGN{B,W,D} insns.  Given two 64-bit
7779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   values (aa,bb), computes, for each lane:
7780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          if aa_lane < 0 then - bb_lane
7782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     else if aa_lane > 0 then bb_lane
7783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     else 0
7784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
7785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* dis_PSIGN_helper ( IRExpr* aax, IRExpr* bbx, Int laneszB )
7786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aa       = newTemp(Ity_I64);
7788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bb       = newTemp(Ity_I64);
7789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp zero     = newTemp(Ity_I64);
7790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bbNeg    = newTemp(Ity_I64);
7791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp negMask  = newTemp(Ity_I64);
7792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp posMask  = newTemp(Ity_I64);
7793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   opSub    = Iop_INVALID;
7794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   opCmpGTS = Iop_INVALID;
7795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (laneszB) {
7797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: opSub = Iop_Sub8x8;  opCmpGTS = Iop_CmpGT8Sx8;  break;
7798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: opSub = Iop_Sub16x4; opCmpGTS = Iop_CmpGT16Sx4; break;
7799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: opSub = Iop_Sub32x2; opCmpGTS = Iop_CmpGT32Sx2; break;
7800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
7801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aa,      aax );
7804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( bb,      bbx );
7805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( zero,    mkU64(0) );
7806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( bbNeg,   binop(opSub,    mkexpr(zero), mkexpr(bb)) );
7807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( negMask, binop(opCmpGTS, mkexpr(zero), mkexpr(aa)) );
7808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( posMask, binop(opCmpGTS, mkexpr(aa),   mkexpr(zero)) );
7809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_Or64,
7812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64, mkexpr(bb),    mkexpr(posMask)),
7813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64, mkexpr(bbNeg), mkexpr(negMask)) );
7814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for the SSSE3 (not SSE3) PABS{B,W,D} insns.  Given a 64-bit
7818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   value aa, computes, for each lane
7819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if aa < 0 then -aa else aa
7821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Note that the result is interpreted as unsigned, so that the
7823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   absolute value of the most negative signed input can be
7824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   represented.
7825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
7826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* dis_PABS_helper ( IRExpr* aax, Int laneszB )
7827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aa      = newTemp(Ity_I64);
7829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp zero    = newTemp(Ity_I64);
7830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aaNeg   = newTemp(Ity_I64);
7831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp negMask = newTemp(Ity_I64);
7832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp posMask = newTemp(Ity_I64);
7833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   opSub   = Iop_INVALID;
7834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   opSarN  = Iop_INVALID;
7835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (laneszB) {
7837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: opSub = Iop_Sub8x8;  opSarN = Iop_SarN8x8;  break;
7838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: opSub = Iop_Sub16x4; opSarN = Iop_SarN16x4; break;
7839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: opSub = Iop_Sub32x2; opSarN = Iop_SarN32x2; break;
7840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
7841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aa,      aax );
7844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( negMask, binop(opSarN, mkexpr(aa), mkU8(8*laneszB-1)) );
7845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( posMask, unop(Iop_Not64, mkexpr(negMask)) );
7846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( zero,    mkU64(0) );
7847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aaNeg,   binop(opSub, mkexpr(zero), mkexpr(aa)) );
7848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_Or64,
7850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64, mkexpr(aa),    mkexpr(posMask)),
7851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64, mkexpr(aaNeg), mkexpr(negMask)) );
7852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* dis_PALIGNR_XMM_helper ( IRTemp hi64,
7855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        IRTemp lo64, Int byteShift )
7856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(byteShift >= 1 && byteShift <= 7);
7858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_Or64,
7860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Shl64, mkexpr(hi64), mkU8(8*(8-byteShift))),
7861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Shr64, mkexpr(lo64), mkU8(8*byteShift))
7862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
7863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate a SIGSEGV followed by a restart of the current instruction
7866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if effective_addr is not 16-aligned.  This is required behaviour
7867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for some SSE3 instructions and all 128-bit SSSE3 instructions.
7868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This assumes that guest_RIP_curr_instr is set correctly! */
7869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void gen_SEGV_if_not_16_aligned ( IRTemp effective_addr )
7870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt(
7872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Exit(
7873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_CmpNE32,
7874663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               binop(Iop_And32,mkexpr(effective_addr),mkU32(0xF)),
7875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU32(0)),
7876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Ijk_SigSEGV,
7877663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         IRConst_U32(guest_EIP_curr_instr),
7878663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         OFFB_EIP
7879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
7880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
7881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for deciding whether a given insn (starting at the opcode
7885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   byte) may validly be used with a LOCK prefix.  The following insns
7886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   may be used with LOCK when their destination operand is in memory.
7887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AFAICS this is exactly the same for both 32-bit and 64-bit mode.
7888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ADD        80 /0,  81 /0,  82 /0,  83 /0,  00,  01
7890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   OR         80 /1,  81 /1,  82 /x,  83 /1,  08,  09
7891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ADC        80 /2,  81 /2,  82 /2,  83 /2,  10,  11
7892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SBB        81 /3,  81 /3,  82 /x,  83 /3,  18,  19
7893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AND        80 /4,  81 /4,  82 /x,  83 /4,  20,  21
7894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SUB        80 /5,  81 /5,  82 /x,  83 /5,  28,  29
7895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XOR        80 /6,  81 /6,  82 /x,  83 /6,  30,  31
7896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DEC        FE /1,  FF /1
7898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   INC        FE /0,  FF /0
7899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NEG        F6 /3,  F7 /3
7901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NOT        F6 /2,  F7 /2
7902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XCHG       86, 87
7904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   BTC        0F BB,  0F BA /7
7906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   BTR        0F B3,  0F BA /6
7907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   BTS        0F AB,  0F BA /5
7908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CMPXCHG    0F B0,  0F B1
7910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CMPXCHG8B  0F C7 /1
7911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XADD       0F C0,  0F C1
7913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------
7915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   80 /0  =  addb $imm8,  rm8
7917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   81 /0  =  addl $imm32, rm32  and  addw $imm16, rm16
7918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   82 /0  =  addb $imm8,  rm8
7919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   83 /0  =  addl $simm8, rm32  and  addw $simm8, rm16
7920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   00     =  addb r8,  rm8
7922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   01     =  addl r32, rm32  and  addw r16, rm16
7923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Same for ADD OR ADC SBB AND SUB XOR
7925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FE /1  = dec rm8
7927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FF /1  = dec rm32  and  dec rm16
7928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FE /0  = inc rm8
7930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FF /0  = inc rm32  and  inc rm16
7931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   F6 /3  = neg rm8
7933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   F7 /3  = neg rm32  and  neg rm16
7934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   F6 /2  = not rm8
7936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   F7 /2  = not rm32  and  not rm16
7937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   0F BB     = btcw r16, rm16    and  btcl r32, rm32
7939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   OF BA /7  = btcw $imm8, rm16  and  btcw $imm8, rm32
7940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Same for BTS, BTR
7942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
7943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool can_be_used_with_LOCK_prefix ( UChar* opc )
7944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (opc[0]) {
7946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x00: case 0x01: case 0x08: case 0x09:
7947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x10: case 0x11: case 0x18: case 0x19:
7948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x20: case 0x21: case 0x28: case 0x29:
7949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x30: case 0x31:
7950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!epartIsReg(opc[1]))
7951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x80: case 0x81: case 0x82: case 0x83:
7955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 6
7956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && !epartIsReg(opc[1]))
7957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFE: case 0xFF:
7961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 1
7962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && !epartIsReg(opc[1]))
7963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF6: case 0xF7:
7967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregOfRM(opc[1]) >= 2 && gregOfRM(opc[1]) <= 3
7968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && !epartIsReg(opc[1]))
7969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x86: case 0x87:
7973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!epartIsReg(opc[1]))
7974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x0F: {
7978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (opc[1]) {
7979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xBB: case 0xB3: case 0xAB:
7980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!epartIsReg(opc[2]))
7981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
7982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xBA:
7984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (gregOfRM(opc[2]) >= 5 && gregOfRM(opc[2]) <= 7
7985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   && !epartIsReg(opc[2]))
7986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
7987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xB0: case 0xB1:
7989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!epartIsReg(opc[2]))
7990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
7991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC7:
7993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (gregOfRM(opc[2]) == 1 && !epartIsReg(opc[2]) )
7994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
7995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0: case 0xC1:
7997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!epartIsReg(opc[2]))
7998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
7999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
8000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
8001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
8002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } /* switch (opc[1]) */
8003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
8004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
8007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
8008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* switch (opc[0]) */
8009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
8011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8013663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengstatic IRTemp math_BSWAP ( IRTemp t1, IRType ty )
8014663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng{
8015663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   IRTemp t2 = newTemp(ty);
8016663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (ty == Ity_I32) {
8017663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      assign( t2,
8018663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         binop(
8019663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            Iop_Or32,
8020663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
8021663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            binop(
8022663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               Iop_Or32,
8023663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
8024663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                mkU32(0x00FF0000)),
8025663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               binop(Iop_Or32,
8026663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
8027663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                      mkU32(0x0000FF00)),
8028663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
8029663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                      mkU32(0x000000FF) )
8030663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            )))
8031663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      );
8032663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      return t2;
8033663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
8034663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (ty == Ity_I16) {
8035663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      assign(t2,
8036663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng             binop(Iop_Or16,
8037663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                   binop(Iop_Shl16, mkexpr(t1), mkU8(8)),
8038663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                   binop(Iop_Shr16, mkexpr(t1), mkU8(8)) ));
8039663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      return t2;
8040663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
8041663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(0);
8042663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /*NOTREACHED*/
8043663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   return IRTemp_INVALID;
8044663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng}
8045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
8047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassemble a single instruction                     ---*/
8048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
8049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Disassemble a single instruction into IR.  The instruction is
8051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   located in host memory at &guest_code[delta].  *expect_CAS is set
8052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to True if the resulting IR is expected to contain an IRCAS
8053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   statement, and False if it's not expected to.  This makes it
8054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   possible for the caller of disInstr_X86_WRK to check that
8055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LOCK-prefixed instructions are at least plausibly translated, in
8056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that it becomes possible to check that a (validly) LOCK-prefixed
8057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction generates a translation containing an IRCAS, and
8058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instructions without LOCK prefixes don't generate translations
8059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   containing an IRCAS.
8060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
8061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
8062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownDisResult disInstr_X86_WRK (
8063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             /*OUT*/Bool* expect_CAS,
8064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
8065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Bool         resteerCisOk,
8066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             void*        callback_opaque,
8067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Long         delta64,
8068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             VexArchInfo* archinfo,
8069436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             VexAbiInfo*  vbi,
8070436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             Bool         sigill_diag
8071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          )
8072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType    ty;
8074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp    addr, t0, t1, t2, t3, t4, t5, t6;
8075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int       alen;
8076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar     opc, modrm, abyte, pre;
8077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt      d32;
8078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar     dis_buf[50];
8079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int       am_sz, d_sz, n_prefixes;
8080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DisResult dres;
8081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar*    insn; /* used in SSE decoders */
8082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The running delta */
8084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int delta = (Int)delta64;
8085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Holds eip at the start of the insn, so that we can print
8087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      consistent error messages for unimplemented insns. */
8088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int delta_start = delta;
8089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* sz denotes the nominal data-op size of the insn; we change it to
8091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      2 if an 0x66 prefix is seen */
8092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int sz = 4;
8093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* sorb holds the segment-override-prefix byte, if any.  Zero if no
8095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
8096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      indicating the prefix.  */
8097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar sorb = 0;
8098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Gets set to True if a LOCK prefix is seen. */
8100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool pfx_lock = False;
8101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set result defaults. */
8103663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres.whatNext    = Dis_Continue;
8104663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres.len         = 0;
8105663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres.continueAt  = 0;
8106663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres.jk_StopHere = Ijk_INVALID;
8107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *expect_CAS = False;
8109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
8111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guest_EIP_bbstart + delta == guest_EIP_curr_instr);
8113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("\t0x%x:  ", guest_EIP_bbstart+delta);
8114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Spot "Special" instructions (see comment at top of file). */
8116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar* code = (UChar*)(guest_code + delta);
8118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Spot the 12-byte preamble:
8119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         C1C703   roll $3,  %edi
8120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         C1C70D   roll $13, %edi
8121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         C1C71D   roll $29, %edi
8122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         C1C713   roll $19, %edi
8123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
8124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (code[ 0] == 0xC1 && code[ 1] == 0xC7 && code[ 2] == 0x03 &&
8125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          code[ 3] == 0xC1 && code[ 4] == 0xC7 && code[ 5] == 0x0D &&
8126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          code[ 6] == 0xC1 && code[ 7] == 0xC7 && code[ 8] == 0x1D &&
8127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          code[ 9] == 0xC1 && code[10] == 0xC7 && code[11] == 0x13) {
8128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Got a "Special" instruction preamble.  Which one is it? */
8129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (code[12] == 0x87 && code[13] == 0xDB /* xchgl %ebx,%ebx */) {
8130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* %EDX = client_request ( %EAX ) */
8131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%%edx = client_request ( %%eax )\n");
8132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 14;
8133663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_lit(&dres, Ijk_ClientReq, guest_EIP_bbstart+delta);
8134663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres.whatNext == Dis_StopHere);
8135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
8136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
8138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (code[12] == 0x87 && code[13] == 0xC9 /* xchgl %ecx,%ecx */) {
8139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* %EAX = guest_NRADDR */
8140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%%eax = guest_NRADDR\n");
8141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 14;
8142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(4, R_EAX, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
8143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
8144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
8146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (code[12] == 0x87 && code[13] == 0xD2 /* xchgl %edx,%edx */) {
8147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* call-noredir *%EAX */
8148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("call-noredir *%%eax\n");
8149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 14;
8150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t1 = newTemp(Ity_I32);
8151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t1, getIReg(4,R_EAX));
8152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I32);
8153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
8154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(4, R_ESP, mkexpr(t2));
8155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta));
8156663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_treg(&dres, Ijk_NoRedir, t1);
8157663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres.whatNext == Dis_StopHere);
8158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
8159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8160436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         else
8161436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (code[12] == 0x87 && code[13] == 0xFF /* xchgl %edi,%edi */) {
8162436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            /* IR injection */
8163436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            DIP("IR injection\n");
8164436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            vex_inject_ir(irsb, Iend_LE);
8165436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
8166436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            // Invalidate the current insn. The reason is that the IRop we're
8167436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            // injecting here can change. In which case the translation has to
8168436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            // be redone. For ease of handling, we simply invalidate all the
8169436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            // time.
8170eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            stmt(IRStmt_Put(OFFB_CMSTART, mkU32(guest_EIP_curr_instr)));
8171eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            stmt(IRStmt_Put(OFFB_CMLEN,   mkU32(14)));
8172436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
8173436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            delta += 14;
8174436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
8175436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_bbstart + delta) ) );
8176436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            dres.whatNext    = Dis_StopHere;
8177eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            dres.jk_StopHere = Ijk_InvalICache;
8178436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            goto decode_success;
8179436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         }
8180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* We don't know what it is. */
8181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
8182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
8183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Handle a couple of weird-ass NOPs that have been observed in the
8187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      wild. */
8188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar* code = (UChar*)(guest_code + delta);
8190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Sun's JVM 1.5.0 uses the following as a NOP:
8191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         26 2E 64 65 90  %es:%cs:%fs:%gs:nop */
8192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (code[0] == 0x26 && code[1] == 0x2E && code[2] == 0x64
8193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && code[3] == 0x65 && code[4] == 0x90) {
8194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%%es:%%cs:%%fs:%%gs:nop\n");
8195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 5;
8196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
8197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Don't barf on recent binutils padding,
8199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         all variants of which are: nopw %cs:0x0(%eax,%eax,1)
8200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66 2e 0f 1f 84 00 00 00 00 00
8201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66 66 2e 0f 1f 84 00 00 00 00 00
8202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66 66 66 2e 0f 1f 84 00 00 00 00 00
8203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
8207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (code[0] == 0x66) {
8208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int data16_cnt;
8209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (data16_cnt = 1; data16_cnt < 6; data16_cnt++)
8210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (code[data16_cnt] != 0x66)
8211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
8212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (code[data16_cnt] == 0x2E && code[data16_cnt + 1] == 0x0F
8213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && code[data16_cnt + 2] == 0x1F && code[data16_cnt + 3] == 0x84
8214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && code[data16_cnt + 4] == 0x00 && code[data16_cnt + 5] == 0x00
8215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && code[data16_cnt + 6] == 0x00 && code[data16_cnt + 7] == 0x00
8216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && code[data16_cnt + 8] == 0x00 ) {
8217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("nopw %%cs:0x0(%%eax,%%eax,1)\n");
8218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 9 + data16_cnt;
8219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
8220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Normal instruction handling starts here. */
8225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Deal with some but not all prefixes:
8227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66(oso)
8228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         F0(lock)
8229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         2E(cs:) 3E(ds:) 26(es:) 64(fs:) 65(gs:) 36(ss:)
8230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Not dealt with (left in place):
8231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         F2 F3
8232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
8233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_prefixes = 0;
8234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (True) {
8235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (n_prefixes > 7) goto decode_failure;
8236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pre = getUChar(delta);
8237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (pre) {
8238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x66:
8239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 2;
8240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
8241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF0:
8242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            pfx_lock = True;
8243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *expect_CAS = True;
8244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
8245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x3E: /* %DS: */
8246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x26: /* %ES: */
8247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x64: /* %FS: */
8248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x65: /* %GS: */
8249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (sorb != 0)
8250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_failure; /* only one seg override allowed */
8251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sorb = pre;
8252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
8253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x2E: { /* %CS: */
8254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* 2E prefix on a conditional branch instruction is a
8255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               branch-prediction hint, which can safely be ignored.  */
8256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UChar op1 = getIByte(delta+1);
8257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UChar op2 = getIByte(delta+2);
8258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((op1 >= 0x70 && op1 <= 0x7F)
8259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                || (op1 == 0xE3)
8260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
8261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0) vex_printf("vex x86->IR: ignoring branch hint\n");
8262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
8263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* All other CS override cases are not handled */
8264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_failure;
8265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
8266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
8267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x36: /* %SS: */
8269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* SS override cases are not handled */
8270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
8271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
8272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto not_a_prefix;
8273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_prefixes++;
8275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
8276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   not_a_prefix:
8279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now we should be looking at the primary opcode byte or the
8281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      leading F2 or F3.  Check that any LOCK prefix is actually
8282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      allowed. */
8283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx_lock) {
8285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (can_be_used_with_LOCK_prefix( (UChar*)&guest_code[delta] )) {
8286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("lock ");
8287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *expect_CAS = False;
8289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
8290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
8295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- The SSE decoder.                             --- */
8296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
8297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* What did I do to deserve SSE ?  Perhaps I was really bad in a
8299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      previous life? */
8300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Note, this doesn't handle SSE2 or SSE3.  That is handled in a
8302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      later section, further on. */
8303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn = (UChar*)&guest_code[delta];
8305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Treat fxsave specially.  It should be doable even on an SSE0
8307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Pentium-II class) CPU.  Hence be prepared to handle it on
8308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      any subarchitecture variant.
8309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
8310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
8312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
8314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRDirty* d;
8315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!epartIsReg(modrm));
8318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
8321b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      gen_SEGV_if_not_16_aligned(addr);
8322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("fxsave %s\n", dis_buf);
8324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Uses dirty helper:
8326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
8327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d = unsafeIRDirty_0_N (
8328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             0/*regparms*/,
8329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             "x86g_dirtyhelper_FXSAVE",
8330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             &x86g_dirtyhelper_FXSAVE,
8331436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
8332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
8333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* declare we're writing memory */
8335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->mFx   = Ifx_Write;
8336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->mAddr = mkexpr(addr);
8337663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      d->mSize = 464; /* according to recent Intel docs */
8338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* declare we're reading guest state */
8340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->nFxState = 7;
8341663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vex_bzero(&d->fxState, sizeof(d->fxState));
8342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].fx     = Ifx_Read;
8344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].offset = OFFB_FTOP;
8345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].size   = sizeof(UInt);
8346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].fx     = Ifx_Read;
8348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].offset = OFFB_FPREGS;
8349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].size   = 8 * sizeof(ULong);
8350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].fx     = Ifx_Read;
8352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].offset = OFFB_FPTAGS;
8353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].size   = 8 * sizeof(UChar);
8354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].fx     = Ifx_Read;
8356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].offset = OFFB_FPROUND;
8357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].size   = sizeof(UInt);
8358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].fx     = Ifx_Read;
8360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].offset = OFFB_FC3210;
8361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].size   = sizeof(UInt);
8362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].fx     = Ifx_Read;
8364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].offset = OFFB_XMM0;
8365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].size   = 8 * sizeof(U128);
8366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].fx     = Ifx_Read;
8368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].offset = OFFB_SSEROUND;
8369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].size   = sizeof(UInt);
8370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 images are packed back-to-back.  If not, the value of
8373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 d->fxState[5].size is wrong. */
8374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(16 == sizeof(U128));
8375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Dirty(d) );
8378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /1 = FXRSTOR m512 -- read x87 and SSE state from memory */
8383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 1) {
8385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRDirty* d;
8386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!epartIsReg(modrm));
8389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
8392b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      gen_SEGV_if_not_16_aligned(addr);
8393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("fxrstor %s\n", dis_buf);
8395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Uses dirty helper:
8397436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            VexEmNote x86g_do_FXRSTOR ( VexGuestX86State*, UInt )
8398b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         NOTE:
8399436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            the VexEmNote value is simply ignored (unlike for FRSTOR)
8400b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      */
8401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d = unsafeIRDirty_0_N (
8402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             0/*regparms*/,
8403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             "x86g_dirtyhelper_FXRSTOR",
8404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             &x86g_dirtyhelper_FXRSTOR,
8405436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
8406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
8407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* declare we're reading memory */
8409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->mFx   = Ifx_Read;
8410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->mAddr = mkexpr(addr);
8411663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      d->mSize = 464; /* according to recent Intel docs */
8412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* declare we're writing guest state */
8414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->nFxState = 7;
8415663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vex_bzero(&d->fxState, sizeof(d->fxState));
8416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].fx     = Ifx_Write;
8418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].offset = OFFB_FTOP;
8419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].size   = sizeof(UInt);
8420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].fx     = Ifx_Write;
8422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].offset = OFFB_FPREGS;
8423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].size   = 8 * sizeof(ULong);
8424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].fx     = Ifx_Write;
8426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].offset = OFFB_FPTAGS;
8427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].size   = 8 * sizeof(UChar);
8428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].fx     = Ifx_Write;
8430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].offset = OFFB_FPROUND;
8431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].size   = sizeof(UInt);
8432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].fx     = Ifx_Write;
8434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].offset = OFFB_FC3210;
8435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].size   = sizeof(UInt);
8436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].fx     = Ifx_Write;
8438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].offset = OFFB_XMM0;
8439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].size   = 8 * sizeof(U128);
8440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].fx     = Ifx_Write;
8442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].offset = OFFB_SSEROUND;
8443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].size   = sizeof(UInt);
8444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 images are packed back-to-back.  If not, the value of
8447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 d->fxState[5].size is wrong. */
8448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(16 == sizeof(U128));
8449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Dirty(d) );
8452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------ SSE decoder main ------ */
8457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Skip parts of the decoder which don't apply given the stated
8459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      guest subarchitecture. */
8460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (archinfo->hwcaps == 0/*baseline, no sse at all*/)
8461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto after_sse_decoders;
8462436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
8463436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* With mmxext only some extended MMX instructions are recognized.
8464436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      The mmxext instructions are MASKMOVQ MOVNTQ PAVGB PAVGW PMAXSW
8465436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      PMAXUB PMINSW PMINUB PMULHUW PSADBW PSHUFW PEXTRW PINSRW PMOVMSKB
8466436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      PREFETCHNTA PREFETCHT0 PREFETCHT1 PREFETCHT2 SFENCE
8467436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
8468436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      http://support.amd.com/us/Embedded_TechDocs/22466.pdf
8469436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      https://en.wikipedia.org/wiki/3DNow!#3DNow.21_extensions */
8470436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
8471436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (archinfo->hwcaps == VEX_HWCAPS_X86_MMXEXT/*integer only sse1 subset*/)
8472436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto mmxext;
8473436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
8474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Otherwise we must be doing sse1 or sse2, so we can at least try
8475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for SSE1 here. */
8476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
8478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
8479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
8480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
8484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
8485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
8487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 55 = ANDNPS -- G = (not G) and E */
8491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
8492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_AndV128 );
8493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 54 = ANDPS -- G = G and E */
8497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
8498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_AndV128 );
8499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
8503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
8504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
8505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
8509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
8510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
8512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2F = COMISS  -- 32F0x4 comparison G,E, and set ZCP */
8516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
8517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
8518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL = newTemp(Ity_F32);
8519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR = newTemp(Ity_F32);
8520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
8523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
8524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)) );
8526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
8529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
8530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("[u]comiss %s,%s\n", dis_buf,
8531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)) );
8532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
8534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
8536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
8537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
8538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_CC_DEP1,
8539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop( Iop_And32,
8540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_CmpF64,
8541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            unop(Iop_F32toF64,mkexpr(argL)),
8542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            unop(Iop_F32toF64,mkexpr(argR))),
8543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(0x45)
8544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          )));
8545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Set NDEP even though it isn't used.  This makes redundant-PUT
8546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         elimination of previous stores to this field work better. */
8547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
8548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
8552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      half xmm */
8553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
8554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg64 = newTemp(Ity_I64);
8555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
8556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
8560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg64, getMMXReg(eregOfRM(modrm)) );
8562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
8563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
8565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
8569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpi2ps %s,%s\n", dis_buf,
8570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
8571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
8574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F(
8576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 0,
8577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_F64toF32,
8578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rmode),
8579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_I32StoF64,
8580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    unop(Iop_64to32, mkexpr(arg64)) )) );
8581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F(
8583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 1,
8584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_F64toF32,
8585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rmode),
8586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_I32StoF64,
8587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    unop(Iop_64HIto32, mkexpr(arg64)) )) );
8588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
8593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      quarter xmm */
8594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
8595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg32 = newTemp(Ity_I32);
8596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
8597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
8600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg32, getIReg(4, eregOfRM(modrm)) );
8602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
8603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
8604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
8605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
8609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsi2ss %s,%s\n", dis_buf,
8610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
8611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
8614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F(
8616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 0,
8617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_F64toF32,
8618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rmode),
8619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_I32StoF64, mkexpr(arg32)) ) );
8620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in mmx, according to prevailing SSE rounding mode */
8626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in mmx, rounding towards zero */
8628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
8629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst64  = newTemp(Ity_I64);
8630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode  = newTemp(Ity_I32);
8631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32lo  = newTemp(Ity_F32);
8632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32hi  = newTemp(Ity_F32);
8633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(insn[1] == 0x2C);
8634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
8636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
8640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
8642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
8644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
8645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
8649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkexpr(addr),
8650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkU32(4) )));
8651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
8652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
8654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
8655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
8658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rmode, mkU32((UInt)Irrm_ZERO) );
8659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
8661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
8664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dst64,
8665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop( Iop_32HLto64,
8666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_F64toI32S,
8667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(rmode),
8668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop( Iop_F32toF64, mkexpr(f32hi) ) ),
8669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_F64toI32S,
8670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(rmode),
8671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop( Iop_F32toF64, mkexpr(f32lo) ) )
8672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
8673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
8674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(gregOfRM(modrm), mkexpr(dst64));
8676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
8680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in ireg, according to prevailing SSE rounding mode */
8681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
8682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in ireg, rounding towards zero */
8683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F
8684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x2D || insn[2] == 0x2C)) {
8685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
8686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32lo = newTemp(Ity_F32);
8687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(insn[2] == 0x2C);
8688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
8691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
8693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
8696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(4, gregOfRM(modrm)));
8697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
8701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
8703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(4, gregOfRM(modrm)));
8704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
8707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, mkU32((UInt)Irrm_ZERO) );
8708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
8710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, gregOfRM(modrm),
8713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_F64toI32S,
8714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(rmode),
8715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop( Iop_F32toF64, mkexpr(f32lo) ) )
8716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
8717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
8722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
8723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
8724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
8729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
8731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
8735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xAE
8736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
8737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp t64 = newTemp(Ity_I64);
8739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp ew = newTemp(Ity_I32);
8740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!epartIsReg(modrm));
8743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
8744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
8747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("ldmxcsr %s\n", dis_buf);
8748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* The only thing we observe in %mxcsr is the rounding mode.
8750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Therefore, pass the 32-bit value (SSE native-format control
8751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         word) to a clean helper, getting back a 64-bit value, the
8752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lower half of which is the SSEROUND value to store, and the
8753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         upper half of which is the emulation-warning token which may
8754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         be generated.
8755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
8756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ULong x86h_check_ldmxcsr ( UInt ); */
8757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t64, mkIRExprCCall(
8758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
8759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "x86g_check_ldmxcsr",
8760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &x86g_check_ldmxcsr,
8761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
8762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )
8763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
8764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
8766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
8767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_emwarn( mkexpr(ew) );
8768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Finally, if an emulation warning was reported, side-exit to
8769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the next insn, reporting the warning, so that Valgrind's
8770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dispatcher sees the warning. */
8771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt(
8772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRStmt_Exit(
8773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
8774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Ijk_EmWarn,
8775663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
8776663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            OFFB_EIP
8777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
8778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
8779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8782436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
8783436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* mmxext sse1 subset starts here. mmxext only arches will parse
8784436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      only this subset of the sse1 instructions. */
8785436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov  mmxext:
8786436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
8787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F F7 = MASKMOVQ -- 8x8 masked store */
8789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF7) {
8790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool ok = False;
8791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMX( &ok, sorb, sz, delta+1 );
8792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!ok)
8793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
8794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8797436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8798436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F E7 = MOVNTQ -- for us, just a plain MMX store.  Note, the
8799436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Intel manual does not say anything about the usual business of
8800436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      the FP reg tags getting trashed whenever an MMX insn happens.
8801436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      So we just leave them alone.
8802436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   */
8803436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (insn[0] == 0x0F && insn[1] == 0xE7) {
8804436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      modrm = getIByte(delta+2);
8805436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (sz == 4 && !epartIsReg(modrm)) {
8806436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         /* do_MMX_preamble(); Intel docs don't specify this */
8807436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8808436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
8809436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("movntq %s,%s\n", dis_buf,
8810436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                               nameMMXReg(gregOfRM(modrm)));
8811436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 2+alen;
8812436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         goto decode_success;
8813436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
8814436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* else fall through */
8815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8817436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8818436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
8819436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
8820436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      do_MMX_preamble();
8821436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_MMXop_regmem_to_reg (
8822436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                sorb, delta+2, insn[1], "pavgb", False );
8823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8826436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8827436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
8828436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
8829436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      do_MMX_preamble();
8830436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_MMXop_regmem_to_reg (
8831436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                sorb, delta+2, insn[1], "pavgw", False );
8832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8835436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8836436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
8837436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      zero-extend of it in ireg(G). */
8838436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (insn[0] == 0x0F && insn[1] == 0xC5) {
8839436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      modrm = insn[2];
8840436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (sz == 4 && epartIsReg(modrm)) {
8841436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         IRTemp sV = newTemp(Ity_I64);
8842436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         t5 = newTemp(Ity_I16);
8843436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         do_MMX_preamble();
8844436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         assign(sV, getMMXReg(eregOfRM(modrm)));
8845436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         breakup64to16s( sV, &t3, &t2, &t1, &t0 );
8846436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         switch (insn[3] & 3) {
8847436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case 0:  assign(t5, mkexpr(t0)); break;
8848436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case 1:  assign(t5, mkexpr(t1)); break;
8849436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case 2:  assign(t5, mkexpr(t2)); break;
8850436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case 3:  assign(t5, mkexpr(t3)); break;
8851436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            default: vassert(0); /*NOTREACHED*/
8852436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         }
8853436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
8854436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("pextrw $%d,%s,%s\n",
8855436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
8856436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                           nameIReg(4,gregOfRM(modrm)));
8857436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 4;
8858436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         goto decode_success;
8859436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
8860436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* else fall through */
8861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8863436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8864436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
8865436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      put it into the specified lane of mmx(G). */
8866436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
8867436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
8868436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         mmx reg.  t4 is the new lane value.  t5 is the original
8869436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         mmx value. t6 is the new mmx value. */
8870436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Int lane;
8871436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      t4 = newTemp(Ity_I16);
8872436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      t5 = newTemp(Ity_I64);
8873436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      t6 = newTemp(Ity_I64);
8874436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      modrm = insn[2];
8875436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      do_MMX_preamble();
8876436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
8877436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign(t5, getMMXReg(gregOfRM(modrm)));
8878436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      breakup64to16s( t5, &t3, &t2, &t1, &t0 );
8879436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
8880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
8881436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         assign(t4, getIReg(2, eregOfRM(modrm)));
8882436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 3+1;
8883436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         lane = insn[3+1-1];
8884436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8885436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                   nameIReg(2,eregOfRM(modrm)),
8886436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                   nameMMXReg(gregOfRM(modrm)));
8887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8889436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 3+alen;
8890436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         lane = insn[3+alen-1];
8891436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         assign(t4, loadLE(Ity_I16, mkexpr(addr)));
8892436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8893436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                   dis_buf,
8894436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                   nameMMXReg(gregOfRM(modrm)));
8895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8897436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      switch (lane & 3) {
8898436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         case 0:  assign(t6, mk64from16s(t3,t2,t1,t4)); break;
8899436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         case 1:  assign(t6, mk64from16s(t3,t2,t4,t0)); break;
8900436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         case 2:  assign(t6, mk64from16s(t3,t4,t1,t0)); break;
8901436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         case 3:  assign(t6, mk64from16s(t4,t2,t1,t0)); break;
8902436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         default: vassert(0); /*NOTREACHED*/
8903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8904436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      putMMXReg(gregOfRM(modrm), mkexpr(t6));
8905436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto decode_success;
8906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8908436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8909436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F EE = PMAXSW -- 16x4 signed max */
8910436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
8911436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      do_MMX_preamble();
8912436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_MMXop_regmem_to_reg (
8913436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                sorb, delta+2, insn[1], "pmaxsw", False );
8914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8917436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8918436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F DE = PMAXUB -- 8x8 unsigned max */
8919436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
8920436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      do_MMX_preamble();
8921436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_MMXop_regmem_to_reg (
8922436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                sorb, delta+2, insn[1], "pmaxub", False );
8923436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto decode_success;
8924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8926436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8927436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F EA = PMINSW -- 16x4 signed min */
8928436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
8929436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      do_MMX_preamble();
8930436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_MMXop_regmem_to_reg (
8931436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                sorb, delta+2, insn[1], "pminsw", False );
8932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8935436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8936436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F DA = PMINUB -- 8x8 unsigned min */
8937436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
8938436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      do_MMX_preamble();
8939436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_MMXop_regmem_to_reg (
8940436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                sorb, delta+2, insn[1], "pminub", False );
8941436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto decode_success;
8942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8944436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8945436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
8946436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      mmx(E), turn them into a byte, and put zero-extend of it in
8947436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ireg(G). */
8948436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
8949436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      modrm = insn[2];
8950436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (epartIsReg(modrm)) {
8951436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         do_MMX_preamble();
8952436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         t0 = newTemp(Ity_I64);
8953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I32);
8954436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         assign(t0, getMMXReg(eregOfRM(modrm)));
8955436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         assign(t1, unop(Iop_8Uto32, unop(Iop_GetMSBs8x8, mkexpr(t0))));
8956436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         putIReg(4, gregOfRM(modrm), mkexpr(t1));
8957436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8958436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 nameIReg(4,gregOfRM(modrm)));
8959436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 3;
8960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
8961436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
8962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
8963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8965436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8966436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
8967436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
8968436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      do_MMX_preamble();
8969436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_MMXop_regmem_to_reg (
8970436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                sorb, delta+2, insn[1], "pmuluh", False );
8971436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto decode_success;
8972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8974436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
8975436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 18 /1 = PREFETCH0   -- with various different hints */
8976436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 18 /2 = PREFETCH1 */
8977436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 18 /3 = PREFETCH2 */
8978436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (insn[0] == 0x0F && insn[1] == 0x18
8979436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov       && !epartIsReg(insn[2])
8980436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov       && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
8981436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* hintstr = "??";
8982436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
8983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
8984436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vassert(!epartIsReg(modrm));
8985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8986436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8987436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta += 2+alen;
8988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8989436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      switch (gregOfRM(modrm)) {
8990436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         case 0: hintstr = "nta"; break;
8991436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         case 1: hintstr = "t0"; break;
8992436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         case 2: hintstr = "t1"; break;
8993436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         case 3: hintstr = "t2"; break;
8994436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         default: vassert(0); /*NOTREACHED*/
8995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8997436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      DIP("prefetch%s %s\n", hintstr, dis_buf);
8998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
8999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9001436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 0D /0 = PREFETCH  m8 -- 3DNow! prefetch */
9002436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 0D /1 = PREFETCHW m8 -- ditto, with some other hint */
9003436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (insn[0] == 0x0F && insn[1] == 0x0D
9004436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov       && !epartIsReg(insn[2])
9005436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov       && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 1) {
9006436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* hintstr = "??";
9007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9008436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      modrm = getIByte(delta+2);
9009436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vassert(!epartIsReg(modrm));
9010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9011436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9012436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta += 2+alen;
9013436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
9014436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      switch (gregOfRM(modrm)) {
9015436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         case 0: hintstr = ""; break;
9016436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         case 1: hintstr = "w"; break;
9017436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         default: vassert(0); /*NOTREACHED*/
9018436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
9019436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
9020436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      DIP("prefetch%s %s\n", hintstr, dis_buf);
9021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9025436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
9026436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF6) {
9027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
9028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
9029436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                 sorb, delta+2, insn[1], "psadbw", False );
9030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9034436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
9035436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
9036436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Int order;
9037436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      IRTemp sV, dV, s3, s2, s1, s0;
9038436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      s3 = s2 = s1 = s0 = IRTemp_INVALID;
9039436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      sV = newTemp(Ity_I64);
9040436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      dV = newTemp(Ity_I64);
9041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
9042436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      modrm = insn[2];
9043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9044436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         assign( sV, getMMXReg(eregOfRM(modrm)) );
9045436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         order = (Int)insn[3];
9046436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 2+2;
9047436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("pshufw $%d,%s,%s\n", order,
9048436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                   nameMMXReg(eregOfRM(modrm)),
9049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
9050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9052436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
9053436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	 order = (Int)insn[2+alen];
9054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9055436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("pshufw $%d,%s,%s\n", order,
9056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
9057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
9058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9059436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      breakup64to16s( sV, &s3, &s2, &s1, &s0 );
9060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9061436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#     define SEL(n) \
9062436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9063436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign(dV,
9064436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9065436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          SEL((order>>2)&3), SEL((order>>0)&3) )
9066436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      );
9067436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      putMMXReg(gregOfRM(modrm), mkexpr(dV));
9068436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#     undef SEL
9069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9072436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F AE /7 = SFENCE -- flush pending operations to memory */
9073436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (insn[0] == 0x0F && insn[1] == 0xAE
9074436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov       && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
9075436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vassert(sz == 4);
9076436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta += 3;
9077436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* Insert a memory fence.  It's sometimes important that these
9078436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         are carried through to the generated code. */
9079436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      stmt( IRStmt_MBE(Imbe_Fence) );
9080436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      DIP("sfence\n");
9081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9084436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* End of mmxext sse1 subset. No more sse parsing for mmxext only arches. */
9085436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (archinfo->hwcaps == VEX_HWCAPS_X86_MMXEXT/*integer only sse1 subset*/)
9086436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto after_sse_decoders;
9087436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
9088436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
9089436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
9090436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
9091436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
9092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9095436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
9096436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
9097436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vassert(sz == 4);
9098436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
9099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9102436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
9103436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
9104436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
9105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9108436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
9109436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
9110436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vassert(sz == 4);
9111436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
9112436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto decode_success;
9113436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
9114436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
9115436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
9116436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
9117436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
9118436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      modrm = getIByte(delta+2);
9119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9120436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         putXMMReg( gregOfRM(modrm),
9121436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    getXMMReg( eregOfRM(modrm) ));
9122436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9123436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                  nameXMMReg(gregOfRM(modrm)));
9124436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 2+1;
9125436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      } else {
9126436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9127436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (insn[1] == 0x28/*movaps*/)
9128436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            gen_SEGV_if_not_16_aligned( addr );
9129436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         putXMMReg( gregOfRM(modrm),
9130436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    loadLE(Ity_V128, mkexpr(addr)) );
9131436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("mov[ua]ps %s,%s\n", dis_buf,
9132436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                  nameXMMReg(gregOfRM(modrm)));
9133436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 2+alen;
9134436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
9135436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto decode_success;
9136436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
9137436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
9138436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
9139436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
9140436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F
9141436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov       && (insn[1] == 0x29 || insn[1] == 0x11)) {
9142436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      modrm = getIByte(delta+2);
9143436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (epartIsReg(modrm)) {
9144436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         /* fall through; awaiting test case */
9145436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      } else {
9146436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9147436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (insn[1] == 0x29/*movaps*/)
9148436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            gen_SEGV_if_not_16_aligned( addr );
9149436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9150436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRM(modrm)),
9151436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                  dis_buf );
9152436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 2+alen;
9153436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         goto decode_success;
9154436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
9155436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
9156436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
9157436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
9158436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
9159436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
9160436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      modrm = getIByte(delta+2);
9161436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (epartIsReg(modrm)) {
9162436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 2+1;
9163436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
9164436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          getXMMRegLane64( eregOfRM(modrm), 0 ) );
9165436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9166436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                               nameXMMReg(gregOfRM(modrm)));
9167436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      } else {
9168436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9169436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 2+alen;
9170436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
9171436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          loadLE(Ity_I64, mkexpr(addr)) );
9172436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("movhps %s,%s\n", dis_buf,
9173436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                               nameXMMReg( gregOfRM(modrm) ));
9174436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
9175436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto decode_success;
9176436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
9177436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
9178436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
9179436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
9180436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (!epartIsReg(insn[2])) {
9181436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 2;
9182436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         addr = disAMode ( &alen, sorb, delta, dis_buf );
9183436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += alen;
9184436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         storeLE( mkexpr(addr),
9185436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  getXMMRegLane64( gregOfRM(insn[2]),
9186436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                   1/*upper lane*/ ) );
9187436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
9188436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                               dis_buf);
9189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
9190436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
9191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
9192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9194436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
9195436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
9196436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
9197436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      modrm = getIByte(delta+2);
9198436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (epartIsReg(modrm)) {
9199436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 2+1;
9200436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         putXMMRegLane64( gregOfRM(modrm),
9201436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          0/*lower lane*/,
9202436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          getXMMRegLane64( eregOfRM(modrm), 1 ));
9203436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
9204436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 nameXMMReg(gregOfRM(modrm)));
9205436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      } else {
9206436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9207436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 2+alen;
9208436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         putXMMRegLane64( gregOfRM(modrm),  0/*lower lane*/,
9209436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          loadLE(Ity_I64, mkexpr(addr)) );
9210436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("movlps %s, %s\n",
9211436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             dis_buf, nameXMMReg( gregOfRM(modrm) ));
9212436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
9213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9216436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
9217436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
9218436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (!epartIsReg(insn[2])) {
9219436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 2;
9220436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         addr = disAMode ( &alen, sorb, delta, dis_buf );
9221436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += alen;
9222436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         storeLE( mkexpr(addr),
9223436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  getXMMRegLane64( gregOfRM(insn[2]),
9224436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                   0/*lower lane*/ ) );
9225436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
9226436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                dis_buf);
9227436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         goto decode_success;
9228436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
9229436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* else fall through */
9230436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
9231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9232436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
9233436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      to 4 lowest bits of ireg(G) */
9234436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (insn[0] == 0x0F && insn[1] == 0x50) {
9235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9236436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (sz == 4 && epartIsReg(modrm)) {
9237436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         Int src;
9238436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         t0 = newTemp(Ity_I32);
9239436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         t1 = newTemp(Ity_I32);
9240436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         t2 = newTemp(Ity_I32);
9241436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         t3 = newTemp(Ity_I32);
9242436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 2+1;
9243436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         src = eregOfRM(modrm);
9244436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         assign( t0, binop( Iop_And32,
9245436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                            binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
9246436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                            mkU32(1) ));
9247436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         assign( t1, binop( Iop_And32,
9248436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                            binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
9249436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                            mkU32(2) ));
9250436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         assign( t2, binop( Iop_And32,
9251436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                            binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
9252436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                            mkU32(4) ));
9253436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         assign( t3, binop( Iop_And32,
9254436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                            binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
9255436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                            mkU32(8) ));
9256436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         putIReg(4, gregOfRM(modrm),
9257436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    binop(Iop_Or32,
9258436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
9259436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
9260436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         )
9261436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                 );
9262436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("movmskps %s,%s\n", nameXMMReg(src),
9263436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 nameIReg(4, gregOfRM(modrm)));
9264436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         goto decode_success;
9265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9266436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* else fall through */
9267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9269436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
9270436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
9271436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (insn[0] == 0x0F && insn[1] == 0x2B) {
9272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9273436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (!epartIsReg(modrm)) {
9274436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9275436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         gen_SEGV_if_not_16_aligned( addr );
9276436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9277436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
9278436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 dis_buf,
9279436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 nameXMMReg(gregOfRM(modrm)));
9280436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 2+alen;
9281436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         goto decode_success;
9282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9283436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* else fall through */
9284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9286436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
9287436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      (lo 1/4 xmm).  If E is mem, upper 3/4 of G is zeroed out. */
9288436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
9289436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vassert(sz == 4);
9290436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      modrm = getIByte(delta+3);
9291436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (epartIsReg(modrm)) {
9292436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         putXMMRegLane32( gregOfRM(modrm), 0,
9293436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          getXMMRegLane32( eregOfRM(modrm), 0 ));
9294436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9295436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                              nameXMMReg(gregOfRM(modrm)));
9296436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 3+1;
9297436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      } else {
9298436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9299436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         /* zero bits 127:64 */
9300436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
9301436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         /* zero bits 63:32 */
9302436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         putXMMRegLane32( gregOfRM(modrm), 1, mkU32(0) );
9303436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         /* write bits 31:0 */
9304436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         putXMMRegLane32( gregOfRM(modrm), 0,
9305436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          loadLE(Ity_I32, mkexpr(addr)) );
9306436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("movss %s,%s\n", dis_buf,
9307436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                              nameXMMReg(gregOfRM(modrm)));
9308436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         delta += 3+alen;
9309436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
9310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9313436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
9314436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      or lo 1/4 xmm). */
9315436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
9316436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vassert(sz == 4);
9317436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      modrm = getIByte(delta+3);
9318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9319436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         /* fall through, we don't yet have a test case */
9320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9321436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9322436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         storeLE( mkexpr(addr),
9323436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  getXMMRegLane32(gregOfRM(modrm), 0) );
9324436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)),
9325436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                              dis_buf);
9326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9327436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         goto decode_success;
9328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9329436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
9330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9331436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
9332436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
9333436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
9334436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto decode_success;
9335436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
9336436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
9337436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
9338436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
9339436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vassert(sz == 4);
9340436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
9341436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto decode_success;
9342436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
9343436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
9344436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 0F 56 = ORPS -- G = G and E */
9345436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
9346436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_OrV128 );
9347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
9351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0x53) {
9352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        "rcpps", Iop_Recip32Fx4 );
9355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
9359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
9360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         "rcpss", Iop_Recip32F0x4 );
9363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
9367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0x52) {
9368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        "rsqrtps", Iop_RSqrt32Fx4 );
9371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
9375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
9376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         "rsqrtss", Iop_RSqrt32F0x4 );
9379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
9383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
9384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    select;
9385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV;
9386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_V128);
9388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_V128);
9389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
9391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
9392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
9395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         select = (Int)insn[3];
9396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+2;
9397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("shufps $%d,%s,%s\n", select,
9398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
9399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
9400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         select = (Int)insn[2+alen];
9404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("shufps $%d,%s,%s\n", select,
9406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
9407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
9408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
9414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
9417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
9418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
9419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       SELD((select>>2)&3), SELD((select>>0)&3) )
9420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SELD
9423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SELS
9424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
9429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
9430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        "sqrtps", Iop_Sqrt32Fx4 );
9432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
9437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         "sqrtss", Iop_Sqrt32F0x4 );
9440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
9444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xAE
9445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
9446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!epartIsReg(modrm));
9449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
9452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Fake up a native SSE mxcsr word.  The only thing it depends
9454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         on is SSEROUND[1:0], so call a clean helper to cook it up.
9455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
9456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* UInt x86h_create_mxcsr ( UInt sseround ) */
9457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("stmxcsr %s\n", dis_buf);
9458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr),
9459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkIRExprCCall(
9460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Ity_I32, 0/*regp*/,
9461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "x86g_create_mxcsr", &x86g_create_mxcsr,
9462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkIRExprVec_1( get_sse_roundingmode() )
9463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )
9464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             );
9465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
9469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
9470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
9471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
9475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
9476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
9478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* These just appear to be special cases of SHUFPS */
9484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV;
9486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool hi = toBool(insn[1] == 0x15);
9488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_V128);
9489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_V128);
9490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
9492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
9493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
9496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(eregOfRM(modrm)),
9499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
9500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  dis_buf,
9506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
9507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (hi) {
9513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
9514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
9516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 57 = XORPS -- G = G and E */
9522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
9523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_XorV128 );
9524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
9528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSE decoder.                      --- */
9529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
9530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
9532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the SSE2 decoder.                   --- */
9533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
9534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Skip parts of the decoder which don't apply given the stated
9536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      guest subarchitecture. */
9537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
9538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto after_sse_decoders; /* no SSE2 capabilities */
9539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn = (UChar*)&guest_code[delta];
9541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
9544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
9545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
9550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
9552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
9557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_AndV128 );
9558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 54 = ANDPD -- G = G and E */
9562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
9563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_AndV128 );
9564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
9569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
9570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
9575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
9577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2F = COMISD  -- 64F0x2 comparison G,E, and set ZCP */
9581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
9582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL = newTemp(Ity_F64);
9584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR = newTemp(Ity_F64);
9585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
9588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)) );
9591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("[u]comisd %s,%s\n", dis_buf,
9596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)) );
9597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
9599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
9601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
9602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
9603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_CC_DEP1,
9604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop( Iop_And32,
9605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
9606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(0x45)
9607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          )));
9608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Set NDEP even though it isn't used.  This makes redundant-PUT
9609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         elimination of previous stores to this field work better. */
9610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
9611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      F64 in xmm(G) */
9616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
9617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg64 = newTemp(Ity_I64);
9618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
9621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
9623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
9624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtdq2pd %s,%s\n", dis_buf,
9631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
9635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 0,
9636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)))
9637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
9640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 1,
9641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)))
9642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(G) */
9649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
9650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
9651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRM(modrm)) );
9656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtdq2ps %s,%s\n", dis_buf,
9664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
9668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)  binop( Iop_F64toF32,                    \
9671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(rmode),                   \
9672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_I32StoF64,mkexpr(_t)))
9673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
9675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
9676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
9680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo half xmm(G), and zero upper half */
9686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
9687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
9688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
9692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRM(modrm)) );
9694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
9695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpd2dq %s,%s\n", dis_buf,
9702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
9706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_F64);
9707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_F64);
9708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, unop(Iop_ReinterpI64asF64,
9709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128to64, mkexpr(argV))) );
9710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_ReinterpI64asF64,
9711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128HIto64, mkexpr(argV))) );
9712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)  binop( Iop_F64toI32S,                   \
9714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(rmode),                   \
9715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(_t) )
9716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
9723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in mmx, according to prevailing SSE rounding mode */
9729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in mmx, rounding towards zero */
9731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst64  = newTemp(Ity_I64);
9733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode  = newTemp(Ity_I32);
9734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f64lo  = newTemp(Ity_F64);
9735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f64hi  = newTemp(Ity_F64);
9736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(insn[1] == 0x2C);
9737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
9739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
9745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
9747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
9748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
9752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkexpr(addr),
9753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkU32(8) )));
9754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
9757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
9758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
9761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rmode, mkU32((UInt)Irrm_ZERO) );
9762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
9764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
9767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dst64,
9768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop( Iop_32HLto64,
9769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64hi) ),
9770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo) )
9771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
9772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(gregOfRM(modrm), mkexpr(dst64));
9775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo half xmm(G), and zero upper half */
9780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Note, this is practically identical to CVTPD2DQ.  It would have
9781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      been nicer to merge them together, but the insn[] offsets differ
9782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      by one. */
9783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
9784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
9785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRM(modrm)) );
9790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpd2ps %s,%s\n", dis_buf,
9798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
9802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_F64);
9803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_F64);
9804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, unop(Iop_ReinterpI64asF64,
9805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128to64, mkexpr(argV))) );
9806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_ReinterpI64asF64,
9807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128HIto64, mkexpr(argV))) );
9808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)  binop( Iop_F64toF32,                    \
9810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(rmode),                   \
9811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(_t) )
9812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32(  gregOfRM(modrm), 3, mkU32(0) );
9814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32(  gregOfRM(modrm), 2, mkU32(0) );
9815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
9819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(G) */
9825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
9826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg64 = newTemp(Ity_I64);
9827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Only switch to MMX mode if the source is a MMX register.
9831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            This is inconsistent with all other instructions which
9832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            convert between XMM and (M64 or MMX), which always switch
9833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            to MMX mode even if 64-bit operand is M64 and not MMX.  At
9834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            least, that's what the Intel docs seem to me to say.
9835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Fixes #210264. */
9836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_MMX_preamble();
9837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg64, getMMXReg(eregOfRM(modrm)) );
9838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpi2pd %s,%s\n", dis_buf,
9846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
9850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 0,
9851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)) )
9852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
9855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 1,
9856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)) )
9857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(G) */
9864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
9865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
9866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRM(modrm)) );
9871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtps2dq %s,%s\n", dis_buf,
9879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
9883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is less than ideal.  If it turns out to be a performance
9886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 bottleneck it can be improved. */
9887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)                            \
9888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        binop( Iop_F64toI32S,                   \
9889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rmode),                   \
9890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop( Iop_F32toF64,              \
9891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
9899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      F64 in xmm(G). */
9905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
9906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32lo = newTemp(Ity_F32);
9907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32hi = newTemp(Ity_F32);
9908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
9910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
9912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
9913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( f32hi, loadLE(Ity_F32,
9920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
9921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtps2pd %s,%s\n", dis_buf,
9923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
9924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F( gregOfRM(modrm), 1,
9927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_F32toF64, mkexpr(f32hi)) );
9928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F( gregOfRM(modrm), 0,
9929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_F32toF64, mkexpr(f32lo)) );
9930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
9935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in ireg, according to prevailing SSE rounding mode */
9936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
9937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in ireg, rounding towards zero */
9938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F
9939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x2D || insn[2] == 0x2C)) {
9940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f64lo = newTemp(Ity_F64);
9942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(insn[2] == 0x2C);
9943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
9946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
9948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
9951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(4, gregOfRM(modrm)));
9952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
9958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(4, gregOfRM(modrm)));
9959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
9962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, mkU32((UInt)Irrm_ZERO) );
9963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
9965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, gregOfRM(modrm),
9968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo)) );
9969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
9974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      low 1/4 xmm(G), according to prevailing SSE rounding mode */
9975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
9976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f64lo = newTemp(Ity_F64);
9978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
9981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
9983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
9990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsd2ss %s,%s\n", dis_buf,
9991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
9992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
9995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F(
9996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 0,
9997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
9998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
10004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      half xmm */
10005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
10006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg32 = newTemp(Ity_I32);
10007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg32, getIReg(4, eregOfRM(modrm)) );
10012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
10014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
10015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
10018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsi2sd %s,%s\n", dis_buf,
10020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)) );
10021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
10024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm), 0,
10025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, mkexpr(arg32)) );
10026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
10031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      low half xmm(G) */
10032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
10033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32lo = newTemp(Ity_F32);
10034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
10040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
10042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
10045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtss2sd %s,%s\n", dis_buf,
10047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
10048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F( gregOfRM(modrm), 0,
10051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop( Iop_F32toF64, mkexpr(f32lo) ) );
10052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
10057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo half xmm(G), and zero upper half, rounding towards zero */
10058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
10059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
10060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
10061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRM(modrm)) );
10065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
10068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvttpd2dq %s,%s\n", dis_buf,
10073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)) );
10074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, mkU32((UInt)Irrm_ZERO) );
10077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_F64);
10079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_F64);
10080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, unop(Iop_ReinterpI64asF64,
10081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128to64, mkexpr(argV))) );
10082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_ReinterpI64asF64,
10083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128HIto64, mkexpr(argV))) );
10084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)  binop( Iop_F64toI32S,                   \
10086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(rmode),                   \
10087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(_t) )
10088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
10090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
10091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
10092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
10093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
10095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
10100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(G), rounding towards zero */
10101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
10102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
10103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
10104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRM(modrm)) );
10109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
10112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvttps2dq %s,%s\n", dis_buf,
10117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)) );
10118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, mkU32((UInt)Irrm_ZERO) );
10121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
10122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is less than ideal.  If it turns out to be a performance
10124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 bottleneck it can be improved. */
10125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)                            \
10126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        binop( Iop_F64toI32S,                   \
10127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rmode),                   \
10128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop( Iop_F32toF64,              \
10129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
10130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
10132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
10133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
10134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
10135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
10137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
10142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
10143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
10144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
10148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5E) {
10149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "divsd", Iop_Div64F0x2 );
10151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /5 = LFENCE -- flush pending operations to memory */
10155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /6 = MFENCE -- flush pending operations to memory */
10156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xAE
10157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
10158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
10159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 3;
10161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Insert a memory fence.  It's sometimes important that these
10162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         are carried through to the generated code. */
10163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_MBE(Imbe_Fence) );
10164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
10165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
10169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
10170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
10171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
10175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5F) {
10176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "maxsd", Iop_Max64F0x2 );
10178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
10182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
10183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
10184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
10188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) {
10189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 );
10191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
10195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
10196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
10197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F
10198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
10199436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* wot = insn[1]==0x28 ? "apd" :
10200436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         insn[1]==0x10 ? "upd" : "dqa";
10201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg( eregOfRM(modrm) ));
10205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)),
10206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
10207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (insn[1] == 0x28/*movapd*/ || insn[1] == 0x6F/*movdqa*/)
10211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SEGV_if_not_16_aligned( addr );
10212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_V128, mkexpr(addr)) );
10214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%s %s,%s\n", wot, dis_buf,
10215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
10216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
10222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
10223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F
10224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[1] == 0x29 || insn[1] == 0x11)) {
10225436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* wot = insn[1]==0x29 ? "apd" : "upd";
10226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through; awaiting test case */
10229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (insn[1] == 0x29/*movapd*/)
10232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SEGV_if_not_16_aligned( addr );
10233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRM(modrm)),
10235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf );
10236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
10242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
10243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg(
10247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gregOfRM(modrm),
10248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop( Iop_32UtoV128, getIReg(4, eregOfRM(modrm)) )
10249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
10250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movd %s, %s\n",
10251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
10252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, sorb, delta+2, dis_buf );
10254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg(
10256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gregOfRM(modrm),
10257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
10258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
10259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
10260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
10265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
10266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( 4, eregOfRM(modrm),
10270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane32(gregOfRM(modrm), 0) );
10271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movd %s, %s\n",
10272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
10273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, sorb, delta+2, dis_buf );
10275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
10277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane32(gregOfRM(modrm), 0) );
10278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
10284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
10285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( eregOfRM(modrm),
10289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg(gregOfRM(modrm)) );
10290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(eregOfRM(modrm)));
10292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, sorb, delta+2, dis_buf );
10294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
10296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
10303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Unfortunately can't simply use the MOVDQA case since the
10304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      prefix lengths are different (66 vs F3) */
10305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
10306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg( eregOfRM(modrm) ));
10311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRM(modrm)));
10313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_V128, mkexpr(addr)) );
10318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqu %s,%s\n", dis_buf,
10319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRM(modrm)));
10320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
10326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Unfortunately can't simply use the MOVDQA case since the
10327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      prefix lengths are different (66 vs F3) */
10328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
10329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( eregOfRM(modrm),
10334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg(gregOfRM(modrm)) );
10335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(eregOfRM(modrm)));
10337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, sorb, delta+3, dis_buf );
10339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
10347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
10348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_MMX_preamble();
10352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putMMXReg( gregOfRM(modrm),
10353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMRegLane64( eregOfRM(modrm), 0 ));
10354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameMMXReg(gregOfRM(modrm)));
10356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through, apparently no mem case for this insn */
10360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
10364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* These seems identical to MOVHPS.  This instruction encoding is
10365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      completely crazy. */
10366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
10367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through; apparently reg-reg is not possible */
10370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
10374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
10375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhpd %s,%s\n", dis_buf,
10376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg( gregOfRM(modrm) ));
10377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
10382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Again, this seems identical to MOVHPS. */
10383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
10384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(insn[2])) {
10385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2;
10386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
10387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
10388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
10389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64( gregOfRM(insn[2]),
10390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   1/*upper lane*/ ) );
10391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
10392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               dis_buf);
10393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
10399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Identical to MOVLPS ? */
10400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x12) {
10401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through; apparently reg-reg is not possible */
10404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm),  0/*lower lane*/,
10408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
10409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movlpd %s, %s\n",
10410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             dis_buf, nameXMMReg( gregOfRM(modrm) ));
10411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
10416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Identical to MOVLPS ? */
10417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
10418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(insn[2])) {
10419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2;
10420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
10421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
10422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
10423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64( gregOfRM(insn[2]),
10424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   0/*lower lane*/ ) );
10425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
10426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                dis_buf);
10427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      2 lowest bits of ireg(G) */
10434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0x50) {
10435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2 && epartIsReg(modrm)) {
10437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int src;
10438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t0 = newTemp(Ity_I32);
10439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I32);
10440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         src = eregOfRM(modrm);
10442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t0, binop( Iop_And32,
10443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(1) ));
10445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t1, binop( Iop_And32,
10446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(2) ));
10448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, gregOfRM(modrm),
10449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 );
10451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movmskpd %s,%s\n", nameXMMReg(src),
10452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameIReg(4, gregOfRM(modrm)));
10453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F7 = MASKMOVDQU -- store selected bytes of double quadword */
10459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xF7) {
10460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2 && epartIsReg(modrm)) {
10462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp regD    = newTemp(Ity_V128);
10463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp mask    = newTemp(Ity_V128);
10464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp olddata = newTemp(Ity_V128);
10465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp newdata = newTemp(Ity_V128);
10466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                addr    = newTemp(Ity_I32);
10467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
10469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( regD, getXMMReg( gregOfRM(modrm) ));
10470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Unfortunately can't do the obvious thing with SarN8x16
10472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            here since that can't be re-emitted as SSE2 code - no such
10473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            insn. */
10474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(
10475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mask,
10476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_64HLtoV128,
10477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_SarN8x8,
10478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getXMMRegLane64( eregOfRM(modrm), 1 ),
10479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(7) ),
10480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_SarN8x8,
10481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getXMMRegLane64( eregOfRM(modrm), 0 ),
10482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(7) ) ));
10483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( olddata, loadLE( Ity_V128, mkexpr(addr) ));
10484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( newdata,
10485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_OrV128,
10486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_AndV128,
10487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(regD),
10488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(mask) ),
10489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_AndV128,
10490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(olddata),
10491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_NotV128, mkexpr(mask)))) );
10492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), mkexpr(newdata) );
10493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("maskmovdqu %s,%s\n", nameXMMReg( eregOfRM(modrm) ),
10496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg( gregOfRM(modrm) ) );
10497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xE7) {
10504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2 && !epartIsReg(modrm)) {
10506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
10508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movntdq %s,%s\n", dis_buf,
10510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
10511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xC3) {
10519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(modrm)) {
10522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
10524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movnti %s,%s\n", dis_buf,
10525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIReg(4, gregOfRM(modrm)));
10526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
10533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      or lo half xmm).  */
10534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
10535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+2);
10536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through, awaiting test case */
10538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* dst: lo half copied, hi half zeroed */
10539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
10542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64( gregOfRM(modrm), 0 ));
10543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
10544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi half). */
10551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
10552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_MMX_preamble();
10556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    unop(Iop_64UtoV128, getMMXReg( eregOfRM(modrm) )) );
10558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
10560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through, apparently no mem case for this insn */
10564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
10568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G (lo half xmm).  Upper half of G is zeroed out. */
10569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
10570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G (lo half xmm).  If E is mem, upper half of G is zeroed out.
10571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If E is reg, upper half of G is unchanged. */
10572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x10)
10573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       || (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7E)) {
10574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm), 0,
10578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getXMMRegLane64( eregOfRM(modrm), 0 ));
10579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (insn[0] == 0xF3/*MOVQ*/) {
10580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* zero bits 127:64 */
10581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
10582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movsd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRM(modrm)));
10585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* zero bits 127:64 */
10589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
10590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* write bits 63:0 */
10591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRM(modrm), 0,
10592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
10593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movsd %s,%s\n", dis_buf,
10594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRM(modrm)));
10595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      or lo half xmm). */
10602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x11) {
10603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
10605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( eregOfRM(modrm), 0,
10607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getXMMRegLane64( gregOfRM(modrm), 0 ));
10608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
10609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(eregOfRM(modrm)));
10610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
10614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64(gregOfRM(modrm), 0) );
10615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
10616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              dis_buf);
10617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
10624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
10625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
10629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
10630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
10632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 56 = ORPD -- G = G and E */
10636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
10637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_OrV128 );
10638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
10643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    select;
10644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_V128);
10645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV = newTemp(Ity_V128);
10646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1 = newTemp(Ity_I64);
10647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s0 = newTemp(Ity_I64);
10648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d1 = newTemp(Ity_I64);
10649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d0 = newTemp(Ity_I64);
10650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
10653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
10656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         select = (Int)insn[3];
10657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+2;
10658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("shufpd $%d,%s,%s\n", select,
10659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
10660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
10661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         select = (Int)insn[2+alen];
10665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("shufpd $%d,%s,%s\n", select,
10667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
10668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
10669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( d0, unop(Iop_V128to64,   mkexpr(dV)) );
10673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s0, unop(Iop_V128to64,   mkexpr(sV)) );
10675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SELD(n) mkexpr((n)==0 ? d0 : d1)
10677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SELS(n) mkexpr((n)==0 ? s0 : s1)
10678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
10680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
10681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
10682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
10683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SELD
10685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SELS
10686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
10692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
10693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        "sqrtpd", Iop_Sqrt64Fx2 );
10694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
10699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3,
10701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         "sqrtsd", Iop_Sqrt64F0x2 );
10702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
10707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
10708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
10713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
10715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* These just appear to be special cases of SHUFPS */
10721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1 = newTemp(Ity_I64);
10723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s0 = newTemp(Ity_I64);
10724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d1 = newTemp(Ity_I64);
10725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d0 = newTemp(Ity_I64);
10726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_V128);
10727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV = newTemp(Ity_V128);
10728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   hi = toBool(insn[1] == 0x15);
10729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
10732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
10735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(eregOfRM(modrm)),
10738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
10739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  dis_buf,
10745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
10746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( d0, unop(Iop_V128to64,   mkexpr(dV)) );
10750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s0, unop(Iop_V128to64,   mkexpr(sV)) );
10752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (hi) {
10754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
10756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
10758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
10759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 57 = XORPD -- G = G and E */
10765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
10766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_XorV128 );
10767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6B = PACKSSDW */
10771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
10772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10773b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 "packssdw",
10774b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 Iop_QNarrowBin32Sto16Sx8, True );
10775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 63 = PACKSSWB */
10779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
10780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10781b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 "packsswb",
10782b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 Iop_QNarrowBin16Sto8Sx16, True );
10783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 67 = PACKUSWB */
10787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
10788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10789b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 "packuswb",
10790b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 Iop_QNarrowBin16Sto8Ux16, True );
10791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FC = PADDB */
10795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
10796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddb", Iop_Add8x16, False );
10798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FE = PADDD */
10802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
10803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddd", Iop_Add32x4, False );
10805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F D4 = PADDQ -- add 64x1 */
10810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
10811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
10813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sorb, delta+2, insn[1], "paddq", False );
10814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D4 = PADDQ */
10818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
10819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddq", Iop_Add64x2, False );
10821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FD = PADDW */
10825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
10826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddw", Iop_Add16x8, False );
10828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EC = PADDSB */
10832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
10833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddsb", Iop_QAdd8Sx16, False );
10835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F ED = PADDSW */
10839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
10840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddsw", Iop_QAdd16Sx8, False );
10842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DC = PADDUSB */
10846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
10847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddusb", Iop_QAdd8Ux16, False );
10849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DD = PADDUSW */
10853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
10854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddusw", Iop_QAdd16Ux8, False );
10856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DB = PAND */
10860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
10861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_AndV128 );
10862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DF = PANDN */
10866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
10867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_AndV128 );
10868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E0 = PAVGB */
10872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
10873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pavgb", Iop_Avg8Ux16, False );
10875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E3 = PAVGW */
10879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
10880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pavgw", Iop_Avg16Ux8, False );
10882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 74 = PCMPEQB */
10886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
10887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpeqb", Iop_CmpEQ8x16, False );
10889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 76 = PCMPEQD */
10893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
10894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpeqd", Iop_CmpEQ32x4, False );
10896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 75 = PCMPEQW */
10900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
10901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpeqw", Iop_CmpEQ16x8, False );
10903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 64 = PCMPGTB */
10907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
10908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpgtb", Iop_CmpGT8Sx16, False );
10910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 66 = PCMPGTD */
10914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
10915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpgtd", Iop_CmpGT32Sx4, False );
10917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 65 = PCMPGTW */
10921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
10922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
10923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpgtw", Iop_CmpGT16Sx8, False );
10924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      zero-extend of it in ireg(G). */
10929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xC5) {
10930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2 && epartIsReg(modrm)) {
10932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t5 = newTemp(Ity_V128);
10933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t4 = newTemp(Ity_I16);
10934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t5, getXMMReg(eregOfRM(modrm)));
10935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (insn[3] & 7) {
10937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:  assign(t4, unop(Iop_32to16,   mkexpr(t0))); break;
10938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:  assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
10939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:  assign(t4, unop(Iop_32to16,   mkexpr(t1))); break;
10940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:  assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
10941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4:  assign(t4, unop(Iop_32to16,   mkexpr(t2))); break;
10942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5:  assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
10943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6:  assign(t4, unop(Iop_32to16,   mkexpr(t3))); break;
10944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7:  assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
10945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0); /*NOTREACHED*/
10946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
10948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pextrw $%d,%s,%s\n",
10949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
10950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg(4,gregOfRM(modrm)));
10951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4;
10952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
10958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put it into the specified lane of xmm(G). */
10959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
10960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int lane;
10961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t4 = newTemp(Ity_I16);
10962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t4, getIReg(2, eregOfRM(modrm)));
10966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lane = insn[3+1-1];
10968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(2,eregOfRM(modrm)),
10970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
10971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lane = insn[3+alen-1];
10975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t4, loadLE(Ity_I16, mkexpr(addr)));
10976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
10978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
10979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
10982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
10986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      E(xmm or mem) to G(xmm) */
10987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF5) {
10988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1V  = newTemp(Ity_V128);
10989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2V  = newTemp(Ity_V128);
10990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV   = newTemp(Ity_V128);
10991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1Hi = newTemp(Ity_I64);
10992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1Lo = newTemp(Ity_I64);
10993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2Hi = newTemp(Ity_I64);
10994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2Lo = newTemp(Ity_I64);
10995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi  = newTemp(Ity_I64);
10996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo  = newTemp(Ity_I64);
10997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( s1V, getXMMReg(eregOfRM(modrm)) );
11000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
11003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddwd %s,%s\n", dis_buf,
11008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
11009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2V, getXMMReg(gregOfRM(modrm)) );
11011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1Lo, unop(Iop_V128to64,   mkexpr(s1V)) );
11013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2Lo, unop(Iop_V128to64,   mkexpr(s2V)) );
11015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, mkIRExprCCall(
11016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
11017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "x86g_calculate_mmx_pmaddwd",
11018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &x86g_calculate_mmx_pmaddwd,
11019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
11021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, mkIRExprCCall(
11022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
11023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "x86g_calculate_mmx_pmaddwd",
11024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &x86g_calculate_mmx_pmaddwd,
11025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
11027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EE = PMAXSW -- 16x8 signed max */
11033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
11034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmaxsw", Iop_Max16Sx8, False );
11036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
11040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
11041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmaxub", Iop_Max8Ux16, False );
11043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EA = PMINSW -- 16x8 signed min */
11047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
11048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pminsw", Iop_Min16Sx8, False );
11050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DA = PMINUB -- 8x16 unsigned min */
11054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
11055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pminub", Iop_Min8Ux16, False );
11057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11060436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes
11061436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      in xmm(E), turn them into a byte, and put zero-extend of it in
11062436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ireg(G). */
11063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
11064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
11065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t0 = newTemp(Ity_I64);
11067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I64);
11068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
11069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
11070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t5 = newTemp(Ity_I32);
11071436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         assign(t5,
11072436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                unop(Iop_16Uto32,
11073436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                     binop(Iop_8HLto16,
11074436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                           unop(Iop_GetMSBs8x8, mkexpr(t1)),
11075436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                           unop(Iop_GetMSBs8x8, mkexpr(t0)))));
11076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, gregOfRM(modrm), mkexpr(t5));
11077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameIReg(4,gregOfRM(modrm)));
11079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3;
11080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
11083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
11086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
11087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmulhuw", Iop_MulHi16Ux8, False );
11089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
11093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
11094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmulhw", Iop_MulHi16Sx8, False );
11096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D5 = PMULHL -- 16x8 multiply */
11100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
11101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmullw", Iop_Mul16x8, False );
11103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      0 to form 64-bit result */
11109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
11110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_I64);
11111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV = newTemp(Ity_I64);
11112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
11113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I32);
11114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
11115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
11117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
11118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
11121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
11123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameMMXReg(gregOfRM(modrm)));
11124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmuludq %s,%s\n", dis_buf,
11129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameMMXReg(gregOfRM(modrm)));
11130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, unop(Iop_64to32, mkexpr(dV)) );
11133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_64to32, mkexpr(sV)) );
11134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg( gregOfRM(modrm),
11135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
11136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
11141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      half */
11142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is a really poor translation -- could be improved if
11143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      performance critical */
11144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
11145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV;
11146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
11147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_V128);
11148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_V128);
11149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
11150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
11151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I64);
11152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
11153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
11154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
11157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
11160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmuludq %s,%s\n", dis_buf,
11165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
11166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
11169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
11172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
11173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
11174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
11175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EB = POR */
11179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
11180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_OrV128 );
11181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
11185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      from E(xmm or mem) to G(xmm) */
11186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF6) {
11187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1V  = newTemp(Ity_V128);
11188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2V  = newTemp(Ity_V128);
11189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV   = newTemp(Ity_V128);
11190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1Hi = newTemp(Ity_I64);
11191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1Lo = newTemp(Ity_I64);
11192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2Hi = newTemp(Ity_I64);
11193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2Lo = newTemp(Ity_I64);
11194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi  = newTemp(Ity_I64);
11195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo  = newTemp(Ity_I64);
11196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
11197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( s1V, getXMMReg(eregOfRM(modrm)) );
11199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psadbw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRM(modrm)));
11202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psadbw %s,%s\n", dis_buf,
11207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRM(modrm)));
11208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2V, getXMMReg(gregOfRM(modrm)) );
11210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1Lo, unop(Iop_V128to64,   mkexpr(s1V)) );
11212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2Lo, unop(Iop_V128to64,   mkexpr(s2V)) );
11214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, mkIRExprCCall(
11215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
11216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "x86g_calculate_mmx_psadbw",
11217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &x86g_calculate_mmx_psadbw,
11218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
11220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, mkIRExprCCall(
11221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
11222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "x86g_calculate_mmx_psadbw",
11223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &x86g_calculate_mmx_psadbw,
11224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
11226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
11232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
11233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int order;
11234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV, s3, s2, s1, s0;
11235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_V128);
11237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_V128);
11238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
11239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
11241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         order = (Int)insn[3];
11242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+2;
11243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufd $%d,%s,%s\n", order,
11244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRM(modrm)),
11245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
11246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 order = (Int)insn[2+alen];
11250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufd $%d,%s,%s\n", order,
11252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
11253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
11254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SEL(n) \
11258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dV,
11260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
11261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           SEL((order>>2)&3), SEL((order>>0)&3) )
11262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
11263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SEL
11265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
11269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mem) to G(xmm), and copy lower half */
11270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
11271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int order;
11272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
11273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV   = newTemp(Ity_V128);
11275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV   = newTemp(Ity_V128);
11276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sVhi = newTemp(Ity_I64);
11277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dVhi = newTemp(Ity_I64);
11278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
11281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         order = (Int)insn[4];
11282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4+1;
11283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufhw $%d,%s,%s\n", order,
11284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(eregOfRM(modrm)),
11285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
11286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 order = (Int)insn[3+alen];
11290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4+alen;
11291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufhw $%d,%s,%s\n", order,
11292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    dis_buf,
11293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
11294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
11296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
11297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SEL(n) \
11299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dVhi,
11301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          SEL((order>>2)&3), SEL((order>>0)&3) )
11303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
11304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dV, binop( Iop_64HLtoV128,
11305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(dVhi),
11306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_V128to64, mkexpr(sV))) );
11307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SEL
11309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
11313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mem) to G(xmm), and copy upper half */
11314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
11315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int order;
11316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
11317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV   = newTemp(Ity_V128);
11319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV   = newTemp(Ity_V128);
11320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sVlo = newTemp(Ity_I64);
11321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dVlo = newTemp(Ity_I64);
11322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
11325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         order = (Int)insn[4];
11326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4+1;
11327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshuflw $%d,%s,%s\n", order,
11328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(eregOfRM(modrm)),
11329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
11330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 order = (Int)insn[3+alen];
11334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4+alen;
11335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshuflw $%d,%s,%s\n", order,
11336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    dis_buf,
11337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
11338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
11340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
11341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SEL(n) \
11343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dVlo,
11345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          SEL((order>>2)&3), SEL((order>>0)&3) )
11347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
11348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dV, binop( Iop_64HLtoV128,
11349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_V128HIto64, mkexpr(sV)),
11350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(dVlo) ) );
11351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SEL
11353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 72 /6 ib = PSLLD by immediate */
11357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 6) {
11360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
11361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F2 = PSLLD by E */
11365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
11366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
11367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 73 /7 ib = PSLLDQ by immediate */
11371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 7) {
11374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    imm = (Int)insn[3];
11376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    reg = eregOfRM(insn[2]);
11377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
11378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(imm >= 0 && imm <= 255);
11379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 4;
11380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV    = newTemp(Ity_V128);
11382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV    = newTemp(Ity_V128);
11383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi64  = newTemp(Ity_I64);
11384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo64  = newTemp(Ity_I64);
11385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi64r = newTemp(Ity_I64);
11386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo64r = newTemp(Ity_I64);
11387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm >= 16) {
11389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg(reg, mkV128(0x0000));
11390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sV, getXMMReg(reg) );
11394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm == 0) {
11398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkexpr(lo64) );
11399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkexpr(hi64) );
11400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
11402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm == 8) {
11403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkU64(0) );
11404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkexpr(lo64) );
11405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
11407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm > 8) {
11408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkU64(0) );
11409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, binop( Iop_Shl64,
11410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(lo64),
11411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8( 8*(imm-8) ) ));
11412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, binop( Iop_Shl64,
11414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(lo64),
11415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(8 * imm) ));
11416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r,
11417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_Or64,
11418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl64, mkexpr(hi64),
11419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 * imm)),
11420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shr64, mkexpr(lo64),
11421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 * (8 - imm)) )
11422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      )
11423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
11424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(reg, mkexpr(dV));
11427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 73 /6 ib = PSLLQ by immediate */
11431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 6) {
11434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
11435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F3 = PSLLQ by E */
11439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
11440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
11441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 71 /6 ib = PSLLW by immediate */
11445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 6) {
11448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
11449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F1 = PSLLW by E */
11453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
11454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
11455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 72 /4 ib = PSRAD by immediate */
11459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 4) {
11462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
11463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E2 = PSRAD by E */
11467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
11468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
11469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 71 /4 ib = PSRAW by immediate */
11473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 4) {
11476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
11477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E1 = PSRAW by E */
11481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
11482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
11483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 72 /2 ib = PSRLD by immediate */
11487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 2) {
11490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
11491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D2 = PSRLD by E */
11495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
11496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
11497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 73 /3 ib = PSRLDQ by immediate */
11501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 3) {
11504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    imm = (Int)insn[3];
11506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    reg = eregOfRM(insn[2]);
11507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
11508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(imm >= 0 && imm <= 255);
11509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 4;
11510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV    = newTemp(Ity_V128);
11512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV    = newTemp(Ity_V128);
11513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi64  = newTemp(Ity_I64);
11514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo64  = newTemp(Ity_I64);
11515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi64r = newTemp(Ity_I64);
11516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo64r = newTemp(Ity_I64);
11517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm >= 16) {
11519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg(reg, mkV128(0x0000));
11520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sV, getXMMReg(reg) );
11524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm == 0) {
11528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkexpr(lo64) );
11529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkexpr(hi64) );
11530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
11532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm == 8) {
11533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkU64(0) );
11534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkexpr(hi64) );
11535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
11537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm > 8) {
11538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkU64(0) );
11539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, binop( Iop_Shr64,
11540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(hi64),
11541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8( 8*(imm-8) ) ));
11542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, binop( Iop_Shr64,
11544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(hi64),
11545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(8 * imm) ));
11546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r,
11547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_Or64,
11548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shr64, mkexpr(lo64),
11549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 * imm)),
11550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl64, mkexpr(hi64),
11551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 * (8 - imm)) )
11552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      )
11553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
11554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(reg, mkexpr(dV));
11558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 73 /2 ib = PSRLQ by immediate */
11562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 2) {
11565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
11566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D3 = PSRLQ by E */
11570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
11571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
11572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 71 /2 ib = PSRLW by immediate */
11576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregOfRM(insn[2]) == 2) {
11579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
11580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D1 = PSRLW by E */
11584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
11585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
11586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F8 = PSUBB */
11590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
11591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubb", Iop_Sub8x16, False );
11593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FA = PSUBD */
11597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
11598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubd", Iop_Sub32x4, False );
11600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F FB = PSUBQ -- sub 64x1 */
11605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
11606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
11607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
11608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sorb, delta+2, insn[1], "psubq", False );
11609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FB = PSUBQ */
11613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
11614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubq", Iop_Sub64x2, False );
11616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F9 = PSUBW */
11620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
11621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubw", Iop_Sub16x8, False );
11623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E8 = PSUBSB */
11627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
11628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubsb", Iop_QSub8Sx16, False );
11630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E9 = PSUBSW */
11634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
11635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubsw", Iop_QSub16Sx8, False );
11637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D8 = PSUBSB */
11641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
11642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubusb", Iop_QSub8Ux16, False );
11644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D9 = PSUBSW */
11648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
11649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubusw", Iop_QSub16Ux8, False );
11651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 68 = PUNPCKHBW */
11655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
11656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckhbw",
11658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveHI8x16, True );
11659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6A = PUNPCKHDQ */
11663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
11664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckhdq",
11666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveHI32x4, True );
11667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6D = PUNPCKHQDQ */
11671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
11672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckhqdq",
11674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveHI64x2, True );
11675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 69 = PUNPCKHWD */
11679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
11680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckhwd",
11682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveHI16x8, True );
11683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 60 = PUNPCKLBW */
11687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
11688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpcklbw",
11690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveLO8x16, True );
11691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 62 = PUNPCKLDQ */
11695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
11696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckldq",
11698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveLO32x4, True );
11699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6C = PUNPCKLQDQ */
11703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
11704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpcklqdq",
11706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveLO64x2, True );
11707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 61 = PUNPCKLWD */
11711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
11712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( sorb, delta+2,
11713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpcklwd",
11714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveLO16x8, True );
11715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EF = PXOR */
11719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
11720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_XorV128 );
11721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--    /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--    if (insn[0] == 0x0F && insn[1] == 0xAE
11726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--        && (!epartIsReg(insn[2]))
11727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--        && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       Bool store = gregOfRM(insn[2]) == 0;
11729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       vg_assert(sz == 4);
11730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       pair = disAMode ( cb, sorb, eip+2, dis_buf );
11731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       t1   = LOW24(pair);
11732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       eip += 2+HI8(pair);
11733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--                   Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--                   Lit16, (UShort)insn[2],
11736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--                   TempReg, t1 );
11737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       goto decode_success;
11739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--    }
11740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /7 = CLFLUSH -- flush cache line */
11742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
11743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
11744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is something of a hack.  We need to know the size of the
11746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cache line containing addr.  Since we don't (easily), assume
11747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         256 on the basis that no real cache would have a line that
11748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         big.  It's safe to invalidate more stuff than we need, just
11749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         inefficient. */
11750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt lineszB = 256;
11751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
11754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Round addr down to the start of the containing block. */
11756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
11757eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov               OFFB_CMSTART,
11758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop( Iop_And32,
11759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(addr),
11760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32( ~(lineszB-1) ))) );
11761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11762eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov      stmt( IRStmt_Put(OFFB_CMLEN, mkU32(lineszB) ) );
11763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11764eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov      jmp_lit(&dres, Ijk_InvalICache, (Addr32)(guest_EIP_bbstart+delta));
11765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("clflush %s\n", dis_buf);
11767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
11771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSE2 decoder.                     --- */
11772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
11773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
11775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the SSE3 decoder.                   --- */
11776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
11777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Skip parts of the decoder which don't apply given the stated
11779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      guest subarchitecture. */
11780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE3)) */
11781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* In fact this is highly bogus; we accept SSE3 insns even on a
11782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SSE2-only guest since they turn into IR which can be re-emitted
11783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      successfully on an SSE2 host. */
11784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
11785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto after_sse_decoders; /* no SSE3 capabilities */
11786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn = (UChar*)&guest_code[delta];
11788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
11790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      duplicating some lanes (2:2:0:0). */
11791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
11792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      duplicating some lanes (3:3:1:1). */
11793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0xF3 && insn[1] == 0x0F
11794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x12 || insn[2] == 0x16)) {
11795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s3, s2, s1, s0;
11796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV  = newTemp(Ity_V128);
11797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isH = insn[2] == 0x16;
11798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg( eregOfRM(modrm)) );
11803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(eregOfRM(modrm)),
11805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
11806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
11807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
11810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     dis_buf,
11813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameXMMReg(gregOfRM(modrm)));
11814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(modrm),
11819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isH ? mk128from32s( s3, s3, s1, s1 )
11820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : mk128from32s( s2, s2, s0, s0 ) );
11821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
11825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      duplicating some lanes (0:1:0:1). */
11826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x12) {
11827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_V128);
11828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d0 = newTemp(Ity_I64);
11829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg( eregOfRM(modrm)) );
11833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movddup %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
11835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
11836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
11837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
11840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movddup %s,%s\n", dis_buf,
11841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRM(modrm)));
11842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(modrm), binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
11846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
11850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD0) {
11851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
11852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp eV   = newTemp(Ity_V128);
11853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp gV   = newTemp(Ity_V128);
11854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addV = newTemp(Ity_V128);
11855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp subV = newTemp(Ity_V128);
11856436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      IRTemp rm     = newTemp(Ity_I32);
11857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
11858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, getXMMReg( eregOfRM(modrm)) );
11862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("addsubps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
11864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
11865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("addsubps %s,%s\n", dis_buf,
11869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
11870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( gV, getXMMReg(gregOfRM(modrm)) );
11874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11875436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
11876436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( addV, triop(Iop_Add32Fx4, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
11877436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( subV, triop(Iop_Sub32Fx4, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
11878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( addV, &a3, &a2, &a1, &a0 );
11880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( subV, &s3, &s2, &s1, &s0 );
11881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(modrm), mk128from32s( a3, s2, a1, s0 ));
11883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
11887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD0) {
11888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp eV   = newTemp(Ity_V128);
11889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp gV   = newTemp(Ity_V128);
11890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addV = newTemp(Ity_V128);
11891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp subV = newTemp(Ity_V128);
11892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp a1     = newTemp(Ity_I64);
11893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s0     = newTemp(Ity_I64);
11894436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      IRTemp rm     = newTemp(Ity_I32);
11895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
11897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, getXMMReg( eregOfRM(modrm)) );
11899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
11901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("addsubpd %s,%s\n", dis_buf,
11906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
11907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( gV, getXMMReg(gregOfRM(modrm)) );
11911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11912436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
11913436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( addV, triop(Iop_Add64Fx2, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
11914436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( subV, triop(Iop_Sub64Fx2, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
11915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
11917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s0, unop(Iop_V128to64,   mkexpr(subV) ));
11918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(modrm),
11920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
11921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
11925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
11926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F
11927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x7C || insn[2] == 0x7D)) {
11928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
11929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp eV     = newTemp(Ity_V128);
11930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp gV     = newTemp(Ity_V128);
11931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp leftV  = newTemp(Ity_V128);
11932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rightV = newTemp(Ity_V128);
11933436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      IRTemp rm     = newTemp(Ity_I32);
11934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isAdd  = insn[2] == 0x7C;
11935436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* str = isAdd ? "add" : "sub";
11936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
11937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
11939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, getXMMReg( eregOfRM(modrm)) );
11941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
11943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
11944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("h%sps %s,%s\n", str, dis_buf,
11948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
11949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( gV, getXMMReg(gregOfRM(modrm)) );
11953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( eV, &e3, &e2, &e1, &e0 );
11955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( gV, &g3, &g2, &g1, &g0 );
11956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( leftV,  mk128from32s( e2, e0, g2, g0 ) );
11958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
11959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11960436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
11961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(modrm),
11962436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                 triop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
11963436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       mkexpr(rm), mkexpr(leftV), mkexpr(rightV) ) );
11964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
11968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
11969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
11970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp e1     = newTemp(Ity_I64);
11971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp e0     = newTemp(Ity_I64);
11972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp g1     = newTemp(Ity_I64);
11973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp g0     = newTemp(Ity_I64);
11974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp eV     = newTemp(Ity_V128);
11975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp gV     = newTemp(Ity_V128);
11976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp leftV  = newTemp(Ity_V128);
11977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rightV = newTemp(Ity_V128);
11978436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      IRTemp rm     = newTemp(Ity_I32);
11979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isAdd  = insn[1] == 0x7C;
11980436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* str = isAdd ? "add" : "sub";
11981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
11983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, getXMMReg( eregOfRM(modrm)) );
11985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRM(modrm)));
11987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("h%spd %s,%s\n", str, dis_buf,
11992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRM(modrm)));
11993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( gV, getXMMReg(gregOfRM(modrm)) );
11997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
11999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
12000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
12001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
12002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( leftV,  binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
12004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
12005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12006436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
12007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRM(modrm),
12008436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                 triop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
12009436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       mkexpr(rm), mkexpr(leftV), mkexpr(rightV) ) );
12010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
12014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xF0) {
12015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta+3);
12016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
12018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRM(modrm),
12021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_V128, mkexpr(addr)) );
12022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("lddqu %s,%s\n", dis_buf,
12023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRM(modrm)));
12024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSE3 decoder.                     --- */
12031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the SSSE3 decoder.                  --- */
12035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
12038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Unsigned Bytes (MMX) */
12039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
12040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
12041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV        = newTemp(Ity_I64);
12042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV        = newTemp(Ity_I64);
12043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVoddsSX  = newTemp(Ity_I64);
12044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVevensSX = newTemp(Ity_I64);
12045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dVoddsZX  = newTemp(Ity_I64);
12046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dVevensZX = newTemp(Ity_I64);
12047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
12051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
12054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddubsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameMMXReg(gregOfRM(modrm)));
12057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddubsw %s,%s\n", dis_buf,
12062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameMMXReg(gregOfRM(modrm)));
12063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* compute dV unsigned x sV signed */
12066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVoddsSX,
12067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_SarN16x4, mkexpr(sV), mkU8(8)) );
12068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVevensSX,
12069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_SarN16x4,
12070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_ShlN16x4, mkexpr(sV), mkU8(8)),
12071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(8)) );
12072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dVoddsZX,
12073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_ShrN16x4, mkexpr(dV), mkU8(8)) );
12074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dVevensZX,
12075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_ShrN16x4,
12076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_ShlN16x4, mkexpr(dV), mkU8(8)),
12077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(8)) );
12078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
12080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_QAdd16Sx4,
12082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul16x4, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
12083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul16x4, mkexpr(sVevensSX), mkexpr(dVevensZX))
12084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
12090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Unsigned Bytes (XMM) */
12091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
12093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV        = newTemp(Ity_V128);
12094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV        = newTemp(Ity_V128);
12095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVoddsSX  = newTemp(Ity_V128);
12096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVevensSX = newTemp(Ity_V128);
12097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dVoddsZX  = newTemp(Ity_V128);
12098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dVevensZX = newTemp(Ity_V128);
12099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
12102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
12105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddubsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
12108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddubsw %s,%s\n", dis_buf,
12114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
12115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* compute dV unsigned x sV signed */
12118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVoddsSX,
12119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_SarN16x8, mkexpr(sV), mkU8(8)) );
12120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVevensSX,
12121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_SarN16x8,
12122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_ShlN16x8, mkexpr(sV), mkU8(8)),
12123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(8)) );
12124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dVoddsZX,
12125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_ShrN16x8, mkexpr(dV), mkU8(8)) );
12126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dVevensZX,
12127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_ShrN16x8,
12128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_ShlN16x8, mkexpr(dV), mkU8(8)),
12129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(8)) );
12130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
12132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_QAdd16Sx8,
12134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul16x8, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
12135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul16x8, mkexpr(sVevensSX), mkexpr(dVevensZX))
12136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- these are MMX class insns introduced in SSSE3 ---*** */
12142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 03 = PHADDSW -- 16x4 signed qadd across from E (mem or
12143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mmx) and G to G (mmx). */
12144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 07 = PHSUBSW -- 16x4 signed qsub across from E (mem or
12145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mmx) and G to G (mmx). */
12146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 01 = PHADDW -- 16x4 add across from E (mem or mmx) and G
12147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to G (mmx). */
12148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 05 = PHSUBW -- 16x4 sub across from E (mem or mmx) and G
12149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to G (mmx). */
12150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 02 = PHADDD -- 32x2 add across from E (mem or mmx) and G
12151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to G (mmx). */
12152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 06 = PHSUBD -- 32x2 sub across from E (mem or mmx) and G
12153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to G (mmx). */
12154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
12156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
12157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
12158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
12159436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* str = "???";
12160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opV64  = Iop_INVALID;
12161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opCatO = Iop_CatOddLanes16x4;
12162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opCatE = Iop_CatEvenLanes16x4;
12163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV     = newTemp(Ity_I64);
12164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV     = newTemp(Ity_I64);
12165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
12169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
12170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
12171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x01: opV64 = Iop_Add16x4;   str = "addw";  break;
12172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x05: opV64 = Iop_Sub16x4;   str = "subw";  break;
12173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x02: opV64 = Iop_Add32x2;   str = "addd";  break;
12174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x06: opV64 = Iop_Sub32x2;   str = "subd";  break;
12175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
12176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (insn[2] == 0x02 || insn[2] == 0x06) {
12178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         opCatO = Iop_InterleaveHI32x2;
12179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         opCatE = Iop_InterleaveLO32x2;
12180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
12184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
12187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ph%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameMMXReg(gregOfRM(modrm)));
12190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ph%s %s,%s\n", str, dis_buf,
12195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameMMXReg(gregOfRM(modrm)));
12196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
12199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(opV64,
12201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(opCatE,mkexpr(sV),mkexpr(dV)),
12202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(opCatO,mkexpr(sV),mkexpr(dV))
12203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 03 = PHADDSW -- 16x8 signed qadd across from E (mem or
12209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm) and G to G (xmm). */
12210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 07 = PHSUBSW -- 16x8 signed qsub across from E (mem or
12211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm) and G to G (xmm). */
12212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 01 = PHADDW -- 16x8 add across from E (mem or xmm) and
12213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G to G (xmm). */
12214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 05 = PHSUBW -- 16x8 sub across from E (mem or xmm) and
12215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G to G (xmm). */
12216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 02 = PHADDD -- 32x4 add across from E (mem or xmm) and
12217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G to G (xmm). */
12218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 06 = PHSUBD -- 32x4 sub across from E (mem or xmm) and
12219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G to G (xmm). */
12220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
12223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
12224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
12225436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* str = "???";
12226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opV64  = Iop_INVALID;
12227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opCatO = Iop_CatOddLanes16x4;
12228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opCatE = Iop_CatEvenLanes16x4;
12229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV     = newTemp(Ity_V128);
12230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV     = newTemp(Ity_V128);
12231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi    = newTemp(Ity_I64);
12232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo    = newTemp(Ity_I64);
12233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi    = newTemp(Ity_I64);
12234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo    = newTemp(Ity_I64);
12235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
12239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
12240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
12241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x01: opV64 = Iop_Add16x4;   str = "addw";  break;
12242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x05: opV64 = Iop_Sub16x4;   str = "subw";  break;
12243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x02: opV64 = Iop_Add32x2;   str = "addd";  break;
12244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x06: opV64 = Iop_Sub32x2;   str = "subd";  break;
12245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
12246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (insn[2] == 0x02 || insn[2] == 0x06) {
12248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         opCatO = Iop_InterleaveHI32x2;
12249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         opCatE = Iop_InterleaveLO32x2;
12250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
12253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg( eregOfRM(modrm)) );
12256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ph%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRM(modrm)));
12258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ph%s %s,%s\n", str, dis_buf,
12264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             nameXMMReg(gregOfRM(modrm)));
12265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This isn't a particularly efficient way to compute the
12274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         result, but at least it avoids a proliferation of IROps,
12275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         hence avoids complication all the backends. */
12276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
12277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128,
12279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(opV64,
12280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(opCatE,mkexpr(sHi),mkexpr(sLo)),
12281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(opCatO,mkexpr(sHi),mkexpr(sLo))
12282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ),
12283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(opV64,
12284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(opCatE,mkexpr(dHi),mkexpr(dLo)),
12285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(opCatO,mkexpr(dHi),mkexpr(dLo))
12286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )
12287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and Scale
12293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (MMX) */
12294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
12295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_I64);
12297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV = newTemp(Ity_I64);
12298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
12302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
12305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmulhrsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameMMXReg(gregOfRM(modrm)));
12308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmulhrsw %s,%s\n", dis_buf,
12313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameMMXReg(gregOfRM(modrm)));
12314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
12317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_PMULHRSW_helper( mkexpr(sV), mkexpr(dV) )
12319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and
12324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Scale (XMM) */
12325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV  = newTemp(Ity_V128);
12328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV  = newTemp(Ity_V128);
12329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi = newTemp(Ity_I64);
12330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo = newTemp(Ity_I64);
12331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi = newTemp(Ity_I64);
12332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo = newTemp(Ity_I64);
12333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
12336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
12339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmulhrsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
12342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmulhrsw %s,%s\n", dis_buf,
12348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRM(modrm)));
12349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
12357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128,
12359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PMULHRSW_helper( mkexpr(sHi), mkexpr(dHi) ),
12360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PMULHRSW_helper( mkexpr(sLo), mkexpr(dLo) )
12361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 08 = PSIGNB -- Packed Sign 8x8  (MMX) */
12367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 09 = PSIGNW -- Packed Sign 16x4 (MMX) */
12368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 09 = PSIGND -- Packed Sign 32x2 (MMX) */
12369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
12370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
12371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_I64);
12373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV      = newTemp(Ity_I64);
12374436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* str = "???";
12375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    laneszB = 0;
12376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
12378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x08: laneszB = 1; str = "b"; break;
12379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x09: laneszB = 2; str = "w"; break;
12380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x0A: laneszB = 4; str = "d"; break;
12381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
12382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
12387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
12390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psign%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameMMXReg(gregOfRM(modrm)));
12393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psign%s %s,%s\n", str, dis_buf,
12398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameMMXReg(gregOfRM(modrm)));
12399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
12402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_PSIGN_helper( mkexpr(sV), mkexpr(dV), laneszB )
12404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 08 = PSIGNB -- Packed Sign 8x16 (XMM) */
12409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 09 = PSIGNW -- Packed Sign 16x8 (XMM) */
12410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 09 = PSIGND -- Packed Sign 32x4 (XMM) */
12411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
12413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_V128);
12415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV      = newTemp(Ity_V128);
12416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi     = newTemp(Ity_I64);
12417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo     = newTemp(Ity_I64);
12418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi     = newTemp(Ity_I64);
12419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo     = newTemp(Ity_I64);
12420436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* str = "???";
12421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    laneszB = 0;
12422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
12424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x08: laneszB = 1; str = "b"; break;
12425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x09: laneszB = 2; str = "w"; break;
12426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x0A: laneszB = 4; str = "d"; break;
12427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
12428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
12432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
12435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psign%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameXMMReg(gregOfRM(modrm)));
12438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psign%s %s,%s\n", str, dis_buf,
12444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameXMMReg(gregOfRM(modrm)));
12445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
12453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128,
12455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PSIGN_helper( mkexpr(sHi), mkexpr(dHi), laneszB ),
12456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PSIGN_helper( mkexpr(sLo), mkexpr(dLo), laneszB )
12457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 1C = PABSB -- Packed Absolute Value 8x8  (MMX) */
12463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 1D = PABSW -- Packed Absolute Value 16x4 (MMX) */
12464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 1E = PABSD -- Packed Absolute Value 32x2 (MMX) */
12465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
12466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
12467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_I64);
12469436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* str = "???";
12470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    laneszB = 0;
12471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
12473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1C: laneszB = 1; str = "b"; break;
12474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1D: laneszB = 2; str = "w"; break;
12475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1E: laneszB = 4; str = "d"; break;
12476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
12477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
12484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pabs%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameMMXReg(gregOfRM(modrm)));
12487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pabs%s %s,%s\n", str, dis_buf,
12492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameMMXReg(gregOfRM(modrm)));
12493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
12496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_PABS_helper( mkexpr(sV), laneszB )
12498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 1C = PABSB -- Packed Absolute Value 8x16 (XMM) */
12503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 1D = PABSW -- Packed Absolute Value 16x8 (XMM) */
12504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 1E = PABSD -- Packed Absolute Value 32x4 (XMM) */
12505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
12507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_V128);
12509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi     = newTemp(Ity_I64);
12510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo     = newTemp(Ity_I64);
12511436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* str = "???";
12512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    laneszB = 0;
12513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
12515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1C: laneszB = 1; str = "b"; break;
12516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1D: laneszB = 2; str = "w"; break;
12517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1E: laneszB = 4; str = "d"; break;
12518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
12519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
12525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pabs%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
12528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pabs%s %s,%s\n", str, dis_buf,
12534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
12535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
12541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128,
12543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PABS_helper( mkexpr(sHi), laneszB ),
12544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PABS_helper( mkexpr(sLo), laneszB )
12545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 3A 0F = PALIGNR -- Packed Align Right (MMX) */
12551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
12552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV  = newTemp(Ity_I64);
12554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV  = newTemp(Ity_I64);
12555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res = newTemp(Ity_I64);
12556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
12560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
12563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 = (UInt)insn[3+1];
12564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
12565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("palignr $%d,%s,%s\n",  (Int)d32,
12566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameMMXReg(eregOfRM(modrm)),
12567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameMMXReg(gregOfRM(modrm)));
12568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 = (UInt)insn[3+alen];
12572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
12573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("palignr $%d%s,%s\n", (Int)d32,
12574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
12575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregOfRM(modrm)));
12576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d32 == 0) {
12579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, mkexpr(sV) );
12580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 1 && d32 <= 7) {
12582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res,
12583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Or64,
12584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Shr64, mkexpr(sV), mkU8(8*d32)),
12585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Shl64, mkexpr(dV), mkU8(8*(8-d32))
12586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     )));
12587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 == 8) {
12589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( res, mkexpr(dV) );
12590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 9 && d32 <= 15) {
12592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, binop(Iop_Shr64, mkexpr(dV), mkU8(8*(d32-8))) );
12593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 16 && d32 <= 255) {
12595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, mkU64(0) );
12596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
12598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
12599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg( gregOfRM(modrm), mkexpr(res) );
12601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 0F = PALIGNR -- Packed Align Right (XMM) */
12605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV  = newTemp(Ity_V128);
12608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV  = newTemp(Ity_V128);
12609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi = newTemp(Ity_I64);
12610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo = newTemp(Ity_I64);
12611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi = newTemp(Ity_I64);
12612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo = newTemp(Ity_I64);
12613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rHi = newTemp(Ity_I64);
12614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rLo = newTemp(Ity_I64);
12615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
12618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
12621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 = (UInt)insn[3+1];
12622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
12623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("palignr $%d,%s,%s\n", (Int)d32,
12624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(eregOfRM(modrm)),
12625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
12626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 = (UInt)insn[3+alen];
12631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
12632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("palignr $%d,%s,%s\n", (Int)d32,
12633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    dis_buf,
12634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRM(modrm)));
12635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d32 == 0) {
12643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkexpr(sHi) );
12644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkexpr(sLo) );
12645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 1 && d32 <= 7) {
12647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, dis_PALIGNR_XMM_helper(dLo, sHi, d32) );
12648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, dis_PALIGNR_XMM_helper(sHi, sLo, d32) );
12649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 == 8) {
12651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkexpr(dLo) );
12652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkexpr(sHi) );
12653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 9 && d32 <= 15) {
12655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, dis_PALIGNR_XMM_helper(dHi, dLo, d32-8) );
12656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, dis_PALIGNR_XMM_helper(dLo, sHi, d32-8) );
12657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 == 16) {
12659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkexpr(dHi) );
12660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkexpr(dLo) );
12661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 17 && d32 <= 23) {
12663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-16))) );
12664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, dis_PALIGNR_XMM_helper(dHi, dLo, d32-16) );
12665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 == 24) {
12667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkU64(0) );
12668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkexpr(dHi) );
12669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 25 && d32 <= 31) {
12671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkU64(0) );
12672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-24))) );
12673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d32 >= 32 && d32 <= 255) {
12675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkU64(0) );
12676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkU64(0) );
12677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
12679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
12680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
12682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x8 (MMX) */
12689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4
12690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_I64);
12692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV      = newTemp(Ity_I64);
12693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregOfRM(modrm)) );
12697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregOfRM(modrm)) );
12700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameMMXReg(gregOfRM(modrm)));
12703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufb %s,%s\n", dis_buf,
12708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameMMXReg(gregOfRM(modrm)));
12709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
12712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
12714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_And64,
12715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* permute the lanes */
12716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(
12717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Iop_Perm8x8,
12718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(dV),
12719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_And64, mkexpr(sV), mkU64(0x0707070707070707ULL))
12720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
12721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* mask off lanes which have (index & 0x80) == 0x80 */
12722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop(Iop_Not64, binop(Iop_SarN8x8, mkexpr(sV), mkU8(7)))
12723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x16 (XMM) */
12729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV         = newTemp(Ity_V128);
12732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV         = newTemp(Ity_V128);
12733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi        = newTemp(Ity_I64);
12734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo        = newTemp(Ity_I64);
12735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi        = newTemp(Ity_I64);
12736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo        = newTemp(Ity_I64);
12737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rHi        = newTemp(Ity_I64);
12738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rLo        = newTemp(Ity_I64);
12739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sevens     = newTemp(Ity_I64);
12740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp mask0x80hi = newTemp(Ity_I64);
12741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp mask0x80lo = newTemp(Ity_I64);
12742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp maskBit3hi = newTemp(Ity_I64);
12743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp maskBit3lo = newTemp(Ity_I64);
12744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sAnd7hi    = newTemp(Ity_I64);
12745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sAnd7lo    = newTemp(Ity_I64);
12746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp permdHi    = newTemp(Ity_I64);
12747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp permdLo    = newTemp(Ity_I64);
12748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRM(modrm)) );
12751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRM(modrm)) );
12754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRM(modrm)));
12757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufb %s,%s\n", dis_buf,
12763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRM(modrm)));
12764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sevens, mkU64(0x0707070707070707ULL) );
12772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*
12774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mask0x80hi = Not(SarN8x8(sHi,7))
12775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      maskBit3hi = SarN8x8(ShlN8x8(sHi,4),7)
12776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sAnd7hi    = And(sHi,sevens)
12777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      permdHi    = Or( And(Perm8x8(dHi,sAnd7hi),maskBit3hi),
12778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       And(Perm8x8(dLo,sAnd7hi),Not(maskBit3hi)) )
12779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      rHi        = And(permdHi,mask0x80hi)
12780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
12781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask0x80hi,
12783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sHi),mkU8(7))));
12784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         maskBit3hi,
12787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_SarN8x8,
12788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_ShlN8x8,mkexpr(sHi),mkU8(4)),
12789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(7)));
12790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(sAnd7hi, binop(Iop_And64,mkexpr(sHi),mkexpr(sevens)));
12792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         permdHi,
12795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
12796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_Or64,
12797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
12798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7hi)),
12799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkexpr(maskBit3hi)),
12800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
12801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7hi)),
12802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_Not64,mkexpr(maskBit3hi))) ));
12803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rHi, binop(Iop_And64,mkexpr(permdHi),mkexpr(mask0x80hi)) );
12805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* And the same for the lower half of the result.  What fun. */
12807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask0x80lo,
12810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sLo),mkU8(7))));
12811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         maskBit3lo,
12814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_SarN8x8,
12815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_ShlN8x8,mkexpr(sLo),mkU8(4)),
12816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(7)));
12817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(sAnd7lo, binop(Iop_And64,mkexpr(sLo),mkexpr(sevens)));
12819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         permdLo,
12822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
12823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_Or64,
12824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
12825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7lo)),
12826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkexpr(maskBit3lo)),
12827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
12828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7lo)),
12829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_Not64,mkexpr(maskBit3lo))) ));
12830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rLo, binop(Iop_And64,mkexpr(permdLo),mkexpr(mask0x80lo)) );
12832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
12834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRM(modrm),
12835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12839663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
12840663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* 0F 38 F0 = MOVBE m16/32(E), r16/32(G) */
12841663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* 0F 38 F1 = MOVBE r16/32(G), m16/32(E) */
12842663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if ((sz == 2 || sz == 4)
12843663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng       && insn[0] == 0x0F && insn[1] == 0x38
12844663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng       && (insn[2] == 0xF0 || insn[2] == 0xF1)
12845663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng       && !epartIsReg(insn[3])) {
12846663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
12847663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      modrm = insn[3];
12848663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      addr = disAMode(&alen, sorb, delta + 3, dis_buf);
12849663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      delta += 3 + alen;
12850663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      ty = szToITy(sz);
12851663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      IRTemp src = newTemp(ty);
12852663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
12853663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (insn[2] == 0xF0) { /* LOAD */
12854663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         assign(src, loadLE(ty, mkexpr(addr)));
12855663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         IRTemp dst = math_BSWAP(src, ty);
12856663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         putIReg(sz, gregOfRM(modrm), mkexpr(dst));
12857663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         DIP("movbe %s,%s\n", dis_buf, nameIReg(sz, gregOfRM(modrm)));
12858663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      } else { /* STORE */
12859663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         assign(src, getIReg(sz, gregOfRM(modrm)));
12860663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         IRTemp dst = math_BSWAP(src, ty);
12861663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         storeLE(mkexpr(addr), mkexpr(dst));
12862663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         DIP("movbe %s,%s\n", nameIReg(sz, gregOfRM(modrm)), dis_buf);
12863663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      }
12864663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      goto decode_success;
12865663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
12866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSSE3 decoder.                    --- */
12869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the SSE4 decoder                    --- */
12873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 0B /r ib = ROUNDSD imm8, xmm2/m64, xmm1
12876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Partial implementation only -- only deal with cases where
12877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the rounding mode is specified directly by the immediate byte.)
12878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      66 0F 3A 0A /r ib = ROUNDSS imm8, xmm2/m32, xmm1
12879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Limitations ditto)
12880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
12881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2
12882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x3A
12883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (/*insn[2] == 0x0B || */insn[2] == 0x0A)) {
12884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isD = insn[2] == 0x0B;
12886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src = newTemp(isD ? Ity_F64 : Ity_F32);
12887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res = newTemp(isD ? Ity_F64 : Ity_F32);
12888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    imm = 0;
12889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src,
12894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isD ? getXMMRegLane64F( eregOfRM(modrm), 0 )
12895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : getXMMRegLane32F( eregOfRM(modrm), 0 ) );
12896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = insn[3+1];
12897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (imm & ~3) goto decode_failure;
12898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
12899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "rounds%c $%d,%s,%s\n",
12900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              isD ? 'd' : 's',
12901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm, nameXMMReg( eregOfRM(modrm) ),
12902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   nameXMMReg( gregOfRM(modrm) ) );
12903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, sorb, delta+3, dis_buf );
12905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src, loadLE( isD ? Ity_F64 : Ity_F32, mkexpr(addr) ));
12906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = insn[3+alen];
12907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (imm & ~3) goto decode_failure;
12908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
12909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "roundsd $%d,%s,%s\n",
12910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm, dis_buf, nameXMMReg( gregOfRM(modrm) ) );
12911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* (imm & 3) contains an Intel-encoded rounding mode.  Because
12914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         that encoding is the same as the encoding for IRRoundingMode,
12915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         we can use that value directly in the IR as a rounding
12916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mode. */
12917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(isD ? Iop_RoundF64toInt : Iop_RoundF32toInt,
12918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU32(imm & 3), mkexpr(src)) );
12919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isD)
12921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64F( gregOfRM(modrm), 0, mkexpr(res) );
12922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
12923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane32F( gregOfRM(modrm), 0, mkexpr(res) );
12924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F BD -- LZCNT (count leading zeroes.  An AMD extension,
12929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      which we can only decode if we're sure this is an AMD cpu that
12930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      supports LZCNT, since otherwise it's BSR, which behaves
12931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      differently. */
12932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xBD
12933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && 0 != (archinfo->hwcaps & VEX_HWCAPS_X86_LZCNT)) {
12934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
12935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*IRType*/ ty  = szToITy(sz);
12936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp     src = newTemp(ty);
12937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
12938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(src, getIReg(sz, eregOfRM(modrm)));
12940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("lzcnt%c %s, %s\n", nameISize(sz),
12942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameIReg(sz, eregOfRM(modrm)),
12943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameIReg(sz, gregOfRM(modrm)));
12944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, sorb, delta+3, dis_buf );
12946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(src, loadLE(ty, mkexpr(addr)));
12947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("lzcnt%c %s, %s\n", nameISize(sz), dis_buf,
12949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameIReg(sz, gregOfRM(modrm)));
12950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res = gen_LZCNT(ty, src);
12953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(modrm), mkexpr(res));
12954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Update flags.  This is pretty lame .. perhaps can do better
12956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // if this turns out to be performance critical.
12957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // O S A P are cleared.  Z is set if RESULT == 0.
12958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // C is set if SRC is zero.
12959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src32 = newTemp(Ity_I32);
12960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res32 = newTemp(Ity_I32);
12961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src32, widenUto32(mkexpr(src)));
12962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res32, widenUto32(mkexpr(res)));
12963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oszacp = newTemp(Ity_I32);
12965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
12966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         oszacp,
12967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_Or32,
12968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Shl32,
12969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto32,
12970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_CmpEQ32, mkexpr(res32), mkU32(0))),
12971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU8(X86G_CC_SHIFT_Z)),
12972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Shl32,
12973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto32,
12974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_CmpEQ32, mkexpr(src32), mkU32(0))),
12975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU8(X86G_CC_SHIFT_C))
12976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
12977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
12980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
12981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
12982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(oszacp) ));
12983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSE4 decoder                      --- */
12989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   after_sse_decoders:
12992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- deal with misc 0x67 pfxs (addr size override) -- */
12995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 67 E3 = JCXZ (for JECXZ see below) */
12998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x67 && insn[1] == 0xE3 && sz == 4) {
12999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2;
13000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta ++;
13002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit(
13003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_CmpEQ16, getIReg(2,R_ECX), mkU16(0)),
13004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Ijk_Boring,
13005663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               IRConst_U32(d32),
13006663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               OFFB_EIP
13007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ));
13008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       DIP("jcxz 0x%x\n", d32);
13009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       goto decode_success;
13010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
13013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the baseline insn decoder            -- */
13014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
13015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Get the primary opcode. */
13017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   opc = getIByte(delta); delta++;
13018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We get here if the current insn isn't SSE, or this CPU doesn't
13020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      support SSE. */
13021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (opc) {
13023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ Control flow --------------- */
13025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC2: /* RET imm16 */
13027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getUDisp16(delta);
13028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2;
13029663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      dis_ret(&dres, d32);
13030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("ret %d\n", (Int)d32);
13031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC3: /* RET */
13033663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      dis_ret(&dres, 0);
13034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("ret\n");
13035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xCF: /* IRET */
13038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Note, this is an extremely kludgey and limited implementation
13039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         of iret.  All it really does is:
13040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            popl %EIP; popl %CS; popl %EFLAGS.
13041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         %CS is set but ignored (as it is in (eg) popw %cs)". */
13042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32); /* ESP */
13043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I32); /* new EIP */
13044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t3 = newTemp(Ity_I32); /* new CS */
13045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t4 = newTemp(Ity_I32); /* new EFLAGS */
13046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIReg(4,R_ESP));
13047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(0) )));
13048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t3, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(4) )));
13049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t4, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(8) )));
13050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Get stuff off stack */
13051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(12)));
13052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* set %CS (which is ignored anyway) */
13053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putSReg( R_CS, unop(Iop_32to16, mkexpr(t3)) );
13054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* set %EFLAGS */
13055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      set_EFLAGS_from_value( t4, False/*!emit_AC_emwarn*/, 0/*unused*/ );
13056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* goto new EIP value */
13057663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      jmp_treg(&dres, Ijk_Ret, t2);
13058663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vassert(dres.whatNext == Dis_StopHere);
13059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("iret (very kludgey)\n");
13060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE8: /* CALL J4 */
13063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getUDisp32(delta); delta += 4;
13064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 += (guest_EIP_bbstart+delta);
13065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
13066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d32 == guest_EIP_bbstart+delta && getIByte(delta) >= 0x58
13067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         && getIByte(delta) <= 0x5F) {
13068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Specially treat the position-independent-code idiom
13069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 call X
13070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              X: popl %reg
13071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            as
13072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 movl %eip, %reg.
13073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            since this generates better code, but for no other reason. */
13074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int archReg = getIByte(delta) - 0x58;
13075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* vex_printf("-- fPIC thingy\n"); */
13076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, archReg, mkU32(guest_EIP_bbstart+delta));
13077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++; /* Step over the POP */
13078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
13079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* The normal sequence for a call. */
13081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I32);
13082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
13083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_ESP, mkexpr(t1));
13084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
13085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32 )) {
13086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* follow into the call target. */
13087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext   = Dis_ResteerU;
13088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.continueAt = (Addr64)(Addr32)d32;
13089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
13090663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jmp_lit(&dres, Ijk_Call, d32);
13091663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres.whatNext == Dis_StopHere);
13092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("call 0x%x\n",d32);
13094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--    case 0xC8: /* ENTER */
13098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       d32 = getUDisp16(eip); eip += 2;
13099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       abyte = getIByte(delta); delta++;
13100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
13101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       vg_assert(sz == 4);
13102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       vg_assert(abyte == 0);
13103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
13104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       t1 = newTemp(cb); t2 = newTemp(cb);
13105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr2(cb, GET,   sz, ArchReg, R_EBP, TempReg, t1);
13106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr2(cb, GET,    4, ArchReg, R_ESP, TempReg, t2);
13107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr2(cb, SUB,    4, Literal, 0,     TempReg, t2);
13108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uLiteral(cb, sz);
13109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_ESP);
13110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr2(cb, STORE,  4, TempReg, t1,    TempReg, t2);
13111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_EBP);
13112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       if (d32) {
13113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, SUB,    4, Literal, 0,     TempReg, t2);
13114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uLiteral(cb, d32);
13115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_ESP);
13116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       }
13117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       DIP("enter 0x%x, 0x%x", d32, abyte);
13118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       break;
13119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC9: /* LEAVE */
13121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
13122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIReg(4,R_EBP));
13124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* First PUT ESP looks redundant, but need it because ESP must
13125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         always be up-to-date for Memcheck to work... */
13126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, mkexpr(t1));
13127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, loadLE(Ity_I32,mkexpr(t1)));
13128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_EBP, mkexpr(t2));
13129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
13130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("leave\n");
13131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------- Misc weird-ass insns --------------- */
13134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x27: /* DAA */
13136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2F: /* DAS */
13137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x37: /* AAA */
13138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3F: /* AAS */
13139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* An ugly implementation for some ugly instructions.  Oh
13140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 well. */
13141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4) goto decode_failure;
13142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
13143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I32);
13144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Make up a 32-bit value (t1), with the old value of AX in the
13145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bottom 16 bits, and the old OSZACP bitmask in the upper 16
13146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bits. */
13147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1,
13148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_16HLto32,
13149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   unop(Iop_32to16,
13150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mk_x86g_calculate_eflags_all()),
13151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   getIReg(2, R_EAX)
13152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ));
13153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Call the helper fn, to get a new AX and OSZACP value, and
13154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         poke both back into the guest state.  Also pass the helper
13155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the actual opcode so it knows which of the 4 instructions it
13156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         is doing the computation for. */
13157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(opc == 0x27 || opc == 0x2F || opc == 0x37 || opc == 0x3F);
13158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2,
13159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              mkIRExprCCall(
13160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Ity_I32, 0/*regparm*/, "x86g_calculate_daa_das_aaa_aas",
13161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 &x86g_calculate_daa_das_aaa_aas,
13162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
13163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ));
13164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
13165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
13167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     stmt( IRStmt_Put( OFFB_CC_DEP1,
13169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And32,
13170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
13171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
13172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    | X86G_CC_MASK_A | X86G_CC_MASK_Z
13173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    | X86G_CC_MASK_S| X86G_CC_MASK_O )
13174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            )
13175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      )
13176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
13177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Set NDEP even though it isn't used.  This makes redundant-PUT
13178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        elimination of previous stores to this field work better. */
13179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (opc) {
13181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 0x27: DIP("daa\n"); break;
13182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 0x2F: DIP("das\n"); break;
13183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 0x37: DIP("aaa\n"); break;
13184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 0x3F: DIP("aas\n"); break;
13185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        default: vassert(0);
13186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
13187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     break;
13188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13189f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   case 0xD4: /* AAM */
13190f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   case 0xD5: /* AAD */
13191f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d32 = getIByte(delta); delta++;
13192f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (sz != 4 || d32 != 10) goto decode_failure;
13193f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      t1 = newTemp(Ity_I32);
13194f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      t2 = newTemp(Ity_I32);
13195f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* Make up a 32-bit value (t1), with the old value of AX in the
13196f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         bottom 16 bits, and the old OSZACP bitmask in the upper 16
13197f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         bits. */
13198f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(t1,
13199f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root             binop(Iop_16HLto32,
13200f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                   unop(Iop_32to16,
13201f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                        mk_x86g_calculate_eflags_all()),
13202f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                   getIReg(2, R_EAX)
13203f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            ));
13204f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* Call the helper fn, to get a new AX and OSZACP value, and
13205f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         poke both back into the guest state.  Also pass the helper
13206f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         the actual opcode so it knows which of the 2 instructions it
13207f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         is doing the computation for. */
13208f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(t2,
13209f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              mkIRExprCCall(
13210f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 Ity_I32, 0/*regparm*/, "x86g_calculate_aad_aam",
13211f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 &x86g_calculate_aad_aam,
13212f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
13213f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            ));
13214f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
13215f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
13216f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
13217f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13218f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      stmt( IRStmt_Put( OFFB_CC_DEP1,
13219f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                        binop(Iop_And32,
13220f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                              binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
13221f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                              mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
13222f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                                     | X86G_CC_MASK_A | X86G_CC_MASK_Z
13223f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                                     | X86G_CC_MASK_S| X86G_CC_MASK_O )
13224f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                             )
13225f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                       )
13226f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root          );
13227f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* Set NDEP even though it isn't used.  This makes
13228f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         redundant-PUT elimination of previous stores to this field
13229f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         work better. */
13230f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13231f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
13232f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      DIP(opc == 0xD4 ? "aam\n" : "aad\n");
13233f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      break;
13234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ CWD/CDQ -------------------- */
13236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x98: /* CBW */
13238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4) {
13239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
13240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cwde\n");
13241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(sz == 2);
13243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
13244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cbw\n");
13245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x99: /* CWD/CDQ */
13249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
13250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, R_EDX,
13251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(mkSizedOp(ty,Iop_Sar8),
13252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getIReg(sz, R_EAX),
13253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(sz == 2 ? 15 : 31)) );
13254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
13255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ FPU ops -------------------- */
13258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9E: /* SAHF */
13260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      codegen_SAHF();
13261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sahf\n");
13262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9F: /* LAHF */
13265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      codegen_LAHF();
13266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("lahf\n");
13267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9B: /* FWAIT */
13270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ignore? */
13271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("fwait\n");
13272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD8:
13275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD9:
13276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDA:
13277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDB:
13278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDC:
13279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDD:
13280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDE:
13281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDF: {
13282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int  delta0    = delta;
13283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = False;
13284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_FPU ( &decode_OK, sorb, delta );
13285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK) {
13286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = delta0;
13287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
13288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ INC & DEC ------------------ */
13293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x40: /* INC eAX */
13295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x41: /* INC eCX */
13296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x42: /* INC eDX */
13297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x43: /* INC eBX */
13298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x44: /* INC eSP */
13299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x45: /* INC eBP */
13300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x46: /* INC eSI */
13301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x47: /* INC eDI */
13302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
13303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
13304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(ty);
13305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop(mkSizedOp(ty,Iop_Add8),
13306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getIReg(sz, (UInt)(opc - 0x40)),
13307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU(ty,1)) );
13308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_INC_DEC( True, t1, ty );
13309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
13310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
13311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x48: /* DEC eAX */
13314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x49: /* DEC eCX */
13315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x4A: /* DEC eDX */
13316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x4B: /* DEC eBX */
13317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x4C: /* DEC eSP */
13318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x4D: /* DEC eBP */
13319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x4E: /* DEC eSI */
13320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x4F: /* DEC eDI */
13321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
13322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
13323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(ty);
13324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
13325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getIReg(sz, (UInt)(opc - 0x48)),
13326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU(ty,1)) );
13327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_INC_DEC( False, t1, ty );
13328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
13329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
13330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ INT ------------------------ */
13333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xCC: /* INT 3 */
13335663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      jmp_lit(&dres, Ijk_SigTRAP, ((Addr32)guest_EIP_bbstart)+delta);
13336663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vassert(dres.whatNext == Dis_StopHere);
13337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("int $0x3\n");
13338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xCD: /* INT imm8 */
13341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getIByte(delta); delta++;
13342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* For any of the cases where we emit a jump (that is, for all
13344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         currently handled cases), it's important that all ArchRegs
13345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         carry their up-to-date value at this point.  So we declare an
13346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         end-of-block here, which forces any TempRegs caching ArchRegs
13347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to be flushed. */
13348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13349663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      /* Handle int $0x3F .. $0x4F by synthesising a segfault and a
13350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         restart of this instruction (hence the "-2" two lines below,
13351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to get the restart EIP to be this instruction.  This is
13352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         probably Linux-specific and it would be more correct to only
13353663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         do this if the VexAbiInfo says that is what we should do.
13354663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         This used to handle just 0x40-0x43; Jikes RVM uses a larger
13355663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         range (0x3F-0x49), and this allows some slack as well. */
13356663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (d32 >= 0x3F && d32 <= 0x4F) {
13357663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_SigSEGV, ((Addr32)guest_EIP_bbstart)+delta-2);
13358663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("int $0x%x\n", (Int)d32);
13360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
13361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Handle int $0x80 (linux syscalls), int $0x81 and $0x82
13364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (darwin syscalls).  As part of this, note where we are, so we
13365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         can back up the guest to this point if the syscall needs to
13366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         be restarted. */
13367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d32 == 0x80) {
13368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32(guest_EIP_curr_instr) ) );
13370663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Sys_int128, ((Addr32)guest_EIP_bbstart)+delta);
13371663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("int $0x80\n");
13373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
13374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d32 == 0x81) {
13376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32(guest_EIP_curr_instr) ) );
13378663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Sys_int129, ((Addr32)guest_EIP_bbstart)+delta);
13379663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("int $0x81\n");
13381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
13382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d32 == 0x82) {
13384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32(guest_EIP_curr_instr) ) );
13386663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Sys_int130, ((Addr32)guest_EIP_bbstart)+delta);
13387663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("int $0x82\n");
13389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
13390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* none of the above */
13393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_failure;
13394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ Jcond, byte offset --------- */
13396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xEB: /* Jb (jump, byte offset) */
13398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
13400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
13401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext   = Dis_ResteerU;
13402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.continueAt = (Addr64)(Addr32)d32;
13403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13404663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Boring, d32);
13405663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("jmp-8 0x%x\n", d32);
13408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE9: /* Jv (jump, 16/32 offset) */
13411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4); /* JRS added 2004 July 11 */
13412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta);
13413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += sz;
13414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
13415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext   = Dis_ResteerU;
13416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.continueAt = (Addr64)(Addr32)d32;
13417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13418663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Boring, d32);
13419663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("jmp 0x%x\n", d32);
13422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x70:
13425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x71:
13426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x72: /* JBb/JNAEb (jump below) */
13427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x73: /* JNBb/JAEb (jump not below) */
13428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x74: /* JZb/JEb (jump zero) */
13429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x75: /* JNZb/JNEb (jump not zero) */
13430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x76: /* JBEb/JNAb (jump below or equal) */
13431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x77: /* JNBEb/JAb (jump not below or equal) */
13432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x78: /* JSb (jump negative) */
13433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x79: /* JSb (jump not negative) */
13434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7A: /* JP (jump parity even) */
13435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7B: /* JNP/JPO (jump parity odd) */
13436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7C: /* JLb/JNGEb (jump less) */
13437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7D: /* JGEb/JNLb (jump greater or equal) */
13438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7E: /* JLEb/JNGb (jump less or equal) */
13439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7F: /* JGb/JNLEb (jump greater) */
13440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    { Int    jmpDelta;
13441436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* comment  = "";
13442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jmpDelta = (Int)getSDisp8(delta);
13443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(-128 <= jmpDelta && jmpDelta < 128);
13444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + jmpDelta;
13445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
13446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (resteerCisOk
13447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && vex_control.guest_chase_cond
13448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && (Addr32)d32 != (Addr32)guest_EIP_bbstart
13449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && jmpDelta < 0
13450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
13451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Speculation: assume this backward branch is taken.  So we
13452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            need to emit a side-exit to the insn following this one,
13453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            on the negation of the condition, and continue at the
13454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            branch target address (d32).  If we wind up back at the
13455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            first instruction of the trace, just stop; it's better to
13456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            let the IR loop unroller handle that case. */
13457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Exit(
13458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
13459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Ijk_Boring,
13460663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                  IRConst_U32(guest_EIP_bbstart+delta),
13461663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                  OFFB_EIP ) );
13462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext   = Dis_ResteerC;
13463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.continueAt = (Addr64)(Addr32)d32;
13464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         comment = "(assumed taken)";
13465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
13467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (resteerCisOk
13468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && vex_control.guest_chase_cond
13469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && (Addr32)d32 != (Addr32)guest_EIP_bbstart
13470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && jmpDelta >= 0
13471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && resteerOkFn( callback_opaque,
13472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          (Addr64)(Addr32)(guest_EIP_bbstart+delta)) ) {
13473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Speculation: assume this forward branch is not taken.  So
13474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            we need to emit a side-exit to d32 (the dest) and continue
13475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            disassembling at the insn immediately following this
13476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            one. */
13477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Exit(
13478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mk_x86g_calculate_condition((X86Condcode)(opc - 0x70)),
13479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Ijk_Boring,
13480663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                  IRConst_U32(d32),
13481663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                  OFFB_EIP ) );
13482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext   = Dis_ResteerC;
13483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.continueAt = (Addr64)(Addr32)(guest_EIP_bbstart+delta);
13484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         comment = "(assumed not taken)";
13485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else {
13487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Conservative default translation - end the block at this
13488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            point. */
13489663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jcc_01( &dres, (X86Condcode)(opc - 0x70),
13490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 (Addr32)(guest_EIP_bbstart+delta), d32);
13491663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
13492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("j%s-8 0x%x %s\n", name_X86Condcode(opc - 0x70), d32, comment);
13494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
13496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE3: /* JECXZ (for JCXZ see above) */
13498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4) goto decode_failure;
13499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta ++;
13501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit(
13502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_CmpEQ32, getIReg(4,R_ECX), mkU32(0)),
13503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Ijk_Boring,
13504663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            IRConst_U32(d32),
13505663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            OFFB_EIP
13506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ));
13507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("jecxz 0x%x\n", d32);
13508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
13511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE1: /* LOOPE  disp8: decrement count, jump if count != 0 && ZF==1 */
13512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE2: /* LOOP   disp8: decrement count, jump if count != 0 */
13513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    { /* Again, the docs say this uses ECX/CX as a count depending on
13514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the address size override, not the operand one.  Since we
13515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         don't handle address size overrides, I guess that means
13516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ECX. */
13517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* zbit  = NULL;
13518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* count = NULL;
13519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* cond  = NULL;
13520436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* xtra = NULL;
13521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4) goto decode_failure;
13523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
13525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ECX, binop(Iop_Sub32, getIReg(4,R_ECX), mkU32(1)));
13526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      count = getIReg(4,R_ECX);
13528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cond = binop(Iop_CmpNE32, count, mkU32(0));
13529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (opc) {
13530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xE2:
13531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xtra = "";
13532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
13533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xE1:
13534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xtra = "e";
13535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            zbit = mk_x86g_calculate_condition( X86CondZ );
13536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    cond = mkAnd1(cond, zbit);
13537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
13538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xE0:
13539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xtra = "ne";
13540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            zbit = mk_x86g_calculate_condition( X86CondNZ );
13541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    cond = mkAnd1(cond, zbit);
13542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
13543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
13544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    vassert(0);
13545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13546663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U32(d32), OFFB_EIP) );
13547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("loop%s 0x%x\n", xtra, d32);
13549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
13551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ IMUL ----------------------- */
13553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x69: /* IMUL Iv, Ev, Gv */
13555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
13556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x6B: /* IMUL Ib, Ev, Gv */
13558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
13559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ MOV ------------------------ */
13562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x88: /* MOV Gb,Eb */
13564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_G_E(sorb, 1, delta);
13565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x89: /* MOV Gv,Ev */
13568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_G_E(sorb, sz, delta);
13569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8A: /* MOV Eb,Gb */
13572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_E_G(sorb, 1, delta);
13573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8B: /* MOV Ev,Gv */
13576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_E_G(sorb, sz, delta);
13577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8D: /* LEA M,Gv */
13580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4)
13581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
13582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
13583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm))
13584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
13585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* NOTE!  this is the one place where a segment override prefix
13586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         has no effect on the address calculation.  Therefore we pass
13587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         zero instead of sorb here. */
13588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
13589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
13590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, gregOfRM(modrm), mkexpr(addr));
13591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
13592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameIReg(sz,gregOfRM(modrm)));
13593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
13596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_Sw_Ew(sorb, sz, delta);
13597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
13600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_Ew_Sw(sorb, delta);
13601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA0: /* MOV Ob,AL */
13604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
13605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Fall through ... */
13606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA1: /* MOV Ov,eAX */
13607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getUDisp32(delta); delta += 4;
13608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
13609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = newTemp(Ity_I32);
13610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
13612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
13613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                d32, nameIReg(sz,R_EAX));
13614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA2: /* MOV Ob,AL */
13617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
13618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Fall through ... */
13619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA3: /* MOV eAX,Ov */
13620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getUDisp32(delta); delta += 4;
13621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
13622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = newTemp(Ity_I32);
13623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
13625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
13626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                sorbTxt(sorb), d32);
13627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB0: /* MOV imm,AL */
13630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB1: /* MOV imm,CL */
13631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB2: /* MOV imm,DL */
13632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB3: /* MOV imm,BL */
13633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB4: /* MOV imm,AH */
13634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB5: /* MOV imm,CH */
13635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB6: /* MOV imm,DH */
13636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB7: /* MOV imm,BH */
13637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getIByte(delta); delta += 1;
13638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(1, opc-0xB0, mkU8(d32));
13639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
13640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB8: /* MOV imm,eAX */
13643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB9: /* MOV imm,eCX */
13644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBA: /* MOV imm,eDX */
13645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBB: /* MOV imm,eBX */
13646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBC: /* MOV imm,eSP */
13647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBD: /* MOV imm,eBP */
13648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBE: /* MOV imm,eSI */
13649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBF: /* MOV imm,eDI */
13650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getUDisp(sz,delta); delta += sz;
13651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
13652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
13653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13655436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   case 0xC6: /* C6 /0 = MOV Ib,Eb */
13656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
13657436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto maybe_do_Mov_I_E;
13658436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   case 0xC7: /* C7 /0 = MOV Iv,Ev */
13659436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto maybe_do_Mov_I_E;
13660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13661436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   maybe_do_Mov_I_E:
13662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
13663436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (gregOfRM(modrm) == 0) {
13664436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (epartIsReg(modrm)) {
13665436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            delta++; /* mod/rm byte */
13666436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            d32 = getUDisp(sz,delta); delta += sz;
13667436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
13668436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
13669436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                     nameIReg(sz,eregOfRM(modrm)));
13670436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         } else {
13671436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            addr = disAMode ( &alen, sorb, delta, dis_buf );
13672436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            delta += alen;
13673436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            d32 = getUDisp(sz,delta); delta += sz;
13674436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
13675436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
13676436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         }
13677436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
13678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13679436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      goto decode_failure;
13680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ opl imm, A ----------------- */
13682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x04: /* ADD Ib, AL */
13684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_Add8, True, delta, "add" );
13685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x05: /* ADD Iv, eAX */
13687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Add8, True, delta, "add" );
13688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0C: /* OR Ib, AL */
13691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_Or8, True, delta, "or" );
13692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0D: /* OR Iv, eAX */
13694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
13695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x14: /* ADC Ib, AL */
13698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, True, Iop_Add8, True, delta, "adc" );
13699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x15: /* ADC Iv, eAX */
13701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, True, Iop_Add8, True, delta, "adc" );
13702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1C: /* SBB Ib, AL */
13705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
13706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1D: /* SBB Iv, eAX */
13708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, True, Iop_Sub8, True, delta, "sbb" );
13709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x24: /* AND Ib, AL */
13712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_And8, True, delta, "and" );
13713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x25: /* AND Iv, eAX */
13715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
13716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2C: /* SUB Ib, AL */
13719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_Sub8, True, delta, "sub" );
13720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2D: /* SUB Iv, eAX */
13722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
13723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x34: /* XOR Ib, AL */
13726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_Xor8, True, delta, "xor" );
13727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x35: /* XOR Iv, eAX */
13729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
13730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3C: /* CMP Ib, AL */
13733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_Sub8, False, delta, "cmp" );
13734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3D: /* CMP Iv, eAX */
13736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
13737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA8: /* TEST Ib, AL */
13740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(  1, False, Iop_And8, False, delta, "test" );
13741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA9: /* TEST Iv, eAX */
13743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
13744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ opl Ev, Gv ----------------- */
13747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x02: /* ADD Eb,Gb */
13749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
13750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x03: /* ADD Ev,Gv */
13752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
13753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0A: /* OR Eb,Gb */
13756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
13757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0B: /* OR Ev,Gv */
13759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
13760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x12: /* ADC Eb,Gb */
13763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
13764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x13: /* ADC Ev,Gv */
13766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
13767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1A: /* SBB Eb,Gb */
13770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
13771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1B: /* SBB Ev,Gv */
13773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
13774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x22: /* AND Eb,Gb */
13777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
13778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x23: /* AND Ev,Gv */
13780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
13781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2A: /* SUB Eb,Gb */
13784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
13785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2B: /* SUB Ev,Gv */
13787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
13788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x32: /* XOR Eb,Gb */
13791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
13792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x33: /* XOR Ev,Gv */
13794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
13795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3A: /* CMP Eb,Gb */
13798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
13799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3B: /* CMP Ev,Gv */
13801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
13802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x84: /* TEST Eb,Gb */
13805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
13806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x85: /* TEST Ev,Gv */
13808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
13809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ opl Gv, Ev ----------------- */
13812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x00: /* ADD Gb,Eb */
13814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Add8, True, 1, delta, "add" );
13816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x01: /* ADD Gv,Ev */
13818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Add8, True, sz, delta, "add" );
13820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x08: /* OR Gb,Eb */
13823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Or8, True, 1, delta, "or" );
13825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x09: /* OR Gv,Ev */
13827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Or8, True, sz, delta, "or" );
13829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x10: /* ADC Gb,Eb */
13832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Add8, True, 1, delta, "adc" );
13834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x11: /* ADC Gv,Ev */
13836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Add8, True, sz, delta, "adc" );
13838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x18: /* SBB Gb,Eb */
13841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Sub8, True, 1, delta, "sbb" );
13843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x19: /* SBB Gv,Ev */
13845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Sub8, True, sz, delta, "sbb" );
13847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x20: /* AND Gb,Eb */
13850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_And8, True, 1, delta, "and" );
13852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x21: /* AND Gv,Ev */
13854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_And8, True, sz, delta, "and" );
13856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x28: /* SUB Gb,Eb */
13859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Sub8, True, 1, delta, "sub" );
13861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x29: /* SUB Gv,Ev */
13863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Sub8, True, sz, delta, "sub" );
13865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x30: /* XOR Gb,Eb */
13868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Xor8, True, 1, delta, "xor" );
13870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x31: /* XOR Gv,Ev */
13872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Xor8, True, sz, delta, "xor" );
13874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x38: /* CMP Gb,Eb */
13877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Sub8, False, 1, delta, "cmp" );
13879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x39: /* CMP Gv,Ev */
13881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Iop_Sub8, False, sz, delta, "cmp" );
13883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ POP ------------------------ */
13886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x58: /* POP eAX */
13888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x59: /* POP eCX */
13889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5A: /* POP eDX */
13890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5B: /* POP eBX */
13891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5D: /* POP eBP */
13892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5E: /* POP eSI */
13893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5F: /* POP eDI */
13894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5C: /* POP eSP */
13895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
13896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
13897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, getIReg(4, R_ESP));
13898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
13899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
13900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, opc-0x58, mkexpr(t1));
13901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
13902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9D: /* POPF */
13905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
13906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, getIReg(4, R_ESP));
13908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
13909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
13910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Generate IR to set %EFLAGS{O,S,Z,A,C,P,D,ID,AC} from the
13912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 value in t1. */
13913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      set_EFLAGS_from_value( t1, True/*emit_AC_emwarn*/,
13914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 ((Addr32)guest_EIP_bbstart)+delta );
13915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("popf%c\n", nameISize(sz));
13917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x61: /* POPA */
13920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is almost certainly wrong for sz==2.  So ... */
13921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4) goto decode_failure;
13922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t5 is the old %ESP value. */
13924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t5 = newTemp(Ity_I32);
13925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t5, getIReg(4, R_ESP) );
13926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Reload all the registers, except %esp. */
13928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
13929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
13930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
13931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
13932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ignore saved %ESP */
13933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
13934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
13935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
13936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* and move %ESP back up */
13938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
13939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("popa%c\n", nameISize(sz));
13941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
13942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8F: /* POPL/POPW m32 */
13944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     { Int    len;
13945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       UChar  rm = getIByte(delta);
13946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       /* make sure this instruction is correct POP */
13948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       if (epartIsReg(rm) || gregOfRM(rm) != 0)
13949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          goto decode_failure;
13950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       /* and has correct size */
13951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       if (sz != 4 && sz != 2)
13952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          goto decode_failure;
13953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ty = szToITy(sz);
13954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       t1 = newTemp(Ity_I32); /* stack address */
13956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       t3 = newTemp(ty); /* data */
13957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       /* set t1 to ESP: t1 = ESP */
13958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       assign( t1, getIReg(4, R_ESP) );
13959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       /* load M[ESP] to virtual register t3: t3 = M[t1] */
13960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       assign( t3, loadLE(ty, mkexpr(t1)) );
13961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       /* increase ESP; must be done before the STORE.  Intel manual says:
13963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            If the ESP register is used as a base register for addressing
13964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            a destination operand in memory, the POP instruction computes
13965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            the effective address of the operand after it increments the
13966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ESP register.
13967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       */
13968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
13969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       /* resolve MODR/M */
13971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       addr = disAMode ( &len, sorb, delta, dis_buf);
13972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       storeLE( mkexpr(addr), mkexpr(t3) );
13973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       DIP("pop%c %s\n", sz==2 ? 'w' : 'l', dis_buf);
13975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       delta += len;
13977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       break;
13978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
13979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1F: /* POP %DS */
13981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_pop_segreg( R_DS, sz ); break;
13982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x07: /* POP %ES */
13983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_pop_segreg( R_ES, sz ); break;
13984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x17: /* POP %SS */
13985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_pop_segreg( R_SS, sz ); break;
13986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ PUSH ----------------------- */
13988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x50: /* PUSH eAX */
13990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x51: /* PUSH eCX */
13991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x52: /* PUSH eDX */
13992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x53: /* PUSH eBX */
13993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x55: /* PUSH eBP */
13994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x56: /* PUSH eSI */
13995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x57: /* PUSH eDI */
13996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x54: /* PUSH eSP */
13997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is the Right Way, in that the value to be pushed is
13998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         established before %esp is changed, so that pushl %esp
13999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         correctly pushes the old value. */
14000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
14001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = sz==2 ? Ity_I16 : Ity_I32;
14002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(ty); t2 = newTemp(Ity_I32);
14003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIReg(sz, opc-0x50));
14004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
14005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, mkexpr(t2) );
14006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE(mkexpr(t2),mkexpr(t1));
14007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
14008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x68: /* PUSH Iv */
14012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getUDisp(sz,delta); delta += sz;
14013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_push_I;
14014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x6A: /* PUSH Ib, sign-extended to sz */
14015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32 = getSDisp8(delta); delta += 1;
14016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_push_I;
14017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_push_I:
14018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
14019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32); t2 = newTemp(ty);
14020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
14021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, mkexpr(t1) );
14022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* stop mkU16 asserting if d32 is a negative 16-bit number
14023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (bug #132813) */
14024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ty == Ity_I16)
14025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 &= 0xFFFF;
14026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(t1), mkU(ty,d32) );
14027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("push%c $0x%x\n", nameISize(sz), d32);
14028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9C: /* PUSHF */ {
14031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
14032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
14035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, mkexpr(t1) );
14036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Calculate OSZACP, and patch in fixed fields as per
14038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Intel docs.
14039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         - bit 1 is always 1
14040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         - bit 9 is Interrupt Enable (should always be 1 in user mode?)
14041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
14042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I32);
14043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t2, binop(Iop_Or32,
14044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mk_x86g_calculate_eflags_all(),
14045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32( (1<<1)|(1<<9) ) ));
14046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Patch in the D flag.  This can simply be a copy of bit 10 of
14048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         baseBlock[OFFB_DFLAG]. */
14049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t3 = newTemp(Ity_I32);
14050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t3, binop(Iop_Or32,
14051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(t2),
14052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And32,
14053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              IRExpr_Get(OFFB_DFLAG,Ity_I32),
14054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(1<<10)))
14055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
14056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* And patch in the ID flag. */
14058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t4 = newTemp(Ity_I32);
14059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t4, binop(Iop_Or32,
14060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(t3),
14061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And32,
14062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
14063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               mkU8(21)),
14064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(1<<21)))
14065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
14066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* And patch in the AC flag. */
14068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t5 = newTemp(Ity_I32);
14069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t5, binop(Iop_Or32,
14070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(t4),
14071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And32,
14072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl32, IRExpr_Get(OFFB_ACFLAG,Ity_I32),
14073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               mkU8(18)),
14074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(1<<18)))
14075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
14076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* if sz==2, the stored value needs to be narrowed. */
14078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2)
14079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t5)) );
14080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
14081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        storeLE( mkexpr(t1), mkexpr(t5) );
14082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("pushf%c\n", nameISize(sz));
14084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x60: /* PUSHA */
14088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is almost certainly wrong for sz==2.  So ... */
14089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4) goto decode_failure;
14090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is the Right Way, in that the value to be pushed is
14092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         established before %esp is changed, so that pusha
14093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         correctly pushes the old %esp value.  New value of %esp is
14094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pushed at start. */
14095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t0 is the %ESP value we're going to push. */
14096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I32);
14097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, getIReg(4, R_ESP) );
14098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t5 will be the new %ESP value. */
14100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t5 = newTemp(Ity_I32);
14101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
14102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Update guest state before prodding memory. */
14104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(4, R_ESP, mkexpr(t5));
14105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Dump all the registers. */
14107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
14108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
14109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
14110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
14111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
14112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
14113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
14114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
14115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("pusha%c\n", nameISize(sz));
14117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0E: /* PUSH %CS */
14120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_push_segreg( R_CS, sz ); break;
14121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1E: /* PUSH %DS */
14122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_push_segreg( R_DS, sz ); break;
14123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x06: /* PUSH %ES */
14124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_push_segreg( R_ES, sz ); break;
14125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x16: /* PUSH %SS */
14126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_push_segreg( R_SS, sz ); break;
14127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ SCAS et al ----------------- */
14129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA4: /* MOVS, no REP prefix */
14131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA5:
14132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sorb != 0)
14133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure; /* else dis_string_op asserts */
14134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
14135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  case 0xA6: /* CMPSb, no REP prefix */
14138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  case 0xA7:
14139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sorb != 0)
14140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure; /* else dis_string_op asserts */
14141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
14142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAA: /* STOS, no REP prefix */
14145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAB:
14146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sorb != 0)
14147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure; /* else dis_string_op asserts */
14148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
14149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAC: /* LODS, no REP prefix */
14152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAD:
14153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sorb != 0)
14154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure; /* else dis_string_op asserts */
14155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
14156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAE: /* SCAS, no REP prefix */
14159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAF:
14160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sorb != 0)
14161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure; /* else dis_string_op asserts */
14162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
14163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xFC: /* CLD */
14167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
14168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cld\n");
14169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xFD: /* STD */
14172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
14173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("std\n");
14174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF8: /* CLC */
14177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF9: /* STC */
14178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF5: /* CMC */
14179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I32);
14180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, mk_x86g_calculate_eflags_all() );
14182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (opc) {
14183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF8:
14184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, binop(Iop_And32, mkexpr(t0),
14185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU32(~X86G_CC_MASK_C)));
14186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("clc\n");
14187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
14188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF9:
14189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, binop(Iop_Or32, mkexpr(t0),
14190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        mkU32(X86G_CC_MASK_C)));
14191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("stc\n");
14192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
14193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF5:
14194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, binop(Iop_Xor32, mkexpr(t0),
14195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU32(X86G_CC_MASK_C)));
14196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("cmc\n");
14197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
14198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
14199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("disInstr(x86)(clc/stc/cmc)");
14200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
14202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
14204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Set NDEP even though it isn't used.  This makes redundant-PUT
14205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         elimination of previous stores to this field work better. */
14206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD6: /* SALC */
14210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I32);
14211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0,  binop(Iop_And32,
14213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mk_x86g_calculate_eflags_c(),
14214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU32(1)) );
14215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop(Iop_Sar32,
14216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl32, mkexpr(t0), mkU8(31)),
14217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(31)) );
14218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(1, R_EAX, unop(Iop_32to8, mkexpr(t1)) );
14219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("salc\n");
14220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* REPNE prefix insn */
14223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF2: {
14224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr32 eip_orig = guest_EIP_bbstart + delta_start;
14225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sorb != 0) goto decode_failure;
14226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getIByte(delta); delta++;
14227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
14229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (abyte) {
14231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* According to the Intel manual, "repne movs" should never occur, but
14232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * in practice it has happened, so allow for it here... */
14233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA4: sz = 1;   /* REPNE MOVS<sz> */
14234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA5:
14235663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondNZ, dis_MOVS, sz, eip_orig,
14236663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "repne movs" );
14237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA6: sz = 1;   /* REPNE CMP<sz> */
14240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA7:
14241663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondNZ, dis_CMPS, sz, eip_orig,
14242663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "repne cmps" );
14243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAA: sz = 1;   /* REPNE STOS<sz> */
14246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAB:
14247663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondNZ, dis_STOS, sz, eip_orig,
14248663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "repne stos" );
14249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAE: sz = 1;   /* REPNE SCAS<sz> */
14252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAF:
14253663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondNZ, dis_SCAS, sz, eip_orig,
14254663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "repne scas" );
14255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
14258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
14264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for the rest, it means REP) */
14265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF3: {
14266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr32 eip_orig = guest_EIP_bbstart + delta_start;
14267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getIByte(delta); delta++;
14268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
14270663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
14271663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (sorb != 0 && abyte != 0x0F) goto decode_failure;
14272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (abyte) {
14274663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      case 0x0F:
14275663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         switch (getIByte(delta)) {
14276663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         /* On older CPUs, TZCNT behaves the same as BSF.  */
14277663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         case 0xBC: /* REP BSF Gv,Ev */
14278663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            delta = dis_bs_E_G ( sorb, sz, delta + 1, True );
14279663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            break;
14280663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         /* On older CPUs, LZCNT behaves the same as BSR.  */
14281663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         case 0xBD: /* REP BSR Gv,Ev */
14282663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            delta = dis_bs_E_G ( sorb, sz, delta + 1, False );
14283663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            break;
14284663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         default:
14285663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            goto decode_failure;
14286663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         }
14287663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         break;
14288663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
14289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA4: sz = 1;   /* REP MOVS<sz> */
14290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA5:
14291663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondAlways, dis_MOVS, sz, eip_orig,
14292663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "rep movs" );
14293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA6: sz = 1;   /* REPE CMP<sz> */
14296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA7:
14297663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondZ, dis_CMPS, sz, eip_orig,
14298663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "repe cmps" );
14299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAA: sz = 1;   /* REP STOS<sz> */
14302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAB:
14303663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondAlways, dis_STOS, sz, eip_orig,
14304663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "rep stos" );
14305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAC: sz = 1;   /* REP LODS<sz> */
14308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAD:
14309663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondAlways, dis_LODS, sz, eip_orig,
14310663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "rep lods" );
14311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAE: sz = 1;   /* REPE SCAS<sz> */
14314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAF:
14315663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_REP_op ( &dres, X86CondZ, dis_SCAS, sz, eip_orig,
14316663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                             guest_EIP_bbstart+delta, "repe scas" );
14317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x90:           /* REP NOP (PAUSE) */
14320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* a hint to the P4 re spin-wait loop */
14321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("rep nop (P4 pause)\n");
14322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* "observe" the hint.  The Vex client needs to be careful not
14323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            to cause very long delays as a result, though. */
14324663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Yield, ((Addr32)guest_EIP_bbstart)+delta);
14325663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
14326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC3:           /* REP RET -- same as normal ret? */
14329663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dis_ret(&dres, 0);
14330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("rep ret\n");
14331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
14334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ XCHG ----------------------- */
14340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* XCHG reg,mem automatically asserts LOCK# even without a LOCK
14342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      prefix; hence it must be translated with an IRCAS (at least, the
14343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      memory variant). */
14344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x86: /* XCHG Gb,Eb */
14345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
14346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Fall through ... */
14347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x87: /* XCHG Gv,Ev */
14348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
14350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(ty); t2 = newTemp(ty);
14351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
14352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t1, getIReg(sz, eregOfRM(modrm)));
14353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t2, getIReg(sz, gregOfRM(modrm)));
14354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(sz, gregOfRM(modrm), mkexpr(t1));
14355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(sz, eregOfRM(modrm), mkexpr(t2));
14356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
14357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("xchg%c %s, %s\n",
14358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
14359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameIReg(sz,eregOfRM(modrm)));
14360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *expect_CAS = True;
14362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
14363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t1, loadLE(ty,mkexpr(addr)) );
14364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2, getIReg(sz,gregOfRM(modrm)) );
14365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         casLE( mkexpr(addr),
14366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
14367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
14368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
14369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("xchg%c %s, %s\n", nameISize(sz),
14370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameIReg(sz,gregOfRM(modrm)), dis_buf);
14371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x90: /* XCHG eAX,eAX */
14375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("nop\n");
14376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x91: /* XCHG eAX,eCX */
14378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x92: /* XCHG eAX,eDX */
14379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x93: /* XCHG eAX,eBX */
14380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x94: /* XCHG eAX,eSP */
14381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x95: /* XCHG eAX,eBP */
14382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x96: /* XCHG eAX,eSI */
14383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x97: /* XCHG eAX,eDI */
14384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
14385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ XLAT ----------------------- */
14388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD7: /* XLAT */
14390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4) goto decode_failure; /* sz == 2 is also allowed (0x66) */
14391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(
14392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         1,
14393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         R_EAX/*AL*/,
14394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         loadLE(Ity_I8,
14395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                handleSegOverride(
14396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   sorb,
14397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_Add32,
14398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         getIReg(4, R_EBX),
14399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         unop(Iop_8Uto32, getIReg(1, R_EAX/*AL*/))))));
14400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("xlat%c [ebx]\n", nameISize(sz));
14402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ IN / OUT ----------------------- */
14405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE4: /* IN imm8, AL */
14407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
14408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getIByte(delta); delta++;
14410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, mkU32( abyte & 0xFF ));
14411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX));
14412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_IN;
14413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE5: /* IN imm8, eAX */
14414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
14415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getIByte(delta); delta++;
14417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, mkU32( abyte & 0xFF ));
14418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX));
14419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_IN;
14420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xEC: /* IN %DX, AL */
14421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
14422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         nameIReg(sz,R_EAX));
14426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_IN;
14427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xED: /* IN %DX, eAX */
14428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
14429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         nameIReg(sz,R_EAX));
14433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_IN;
14434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_IN: {
14435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* At this point, sz indicates the width, and t1 is a 32-bit
14436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         value giving port number. */
14437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRDirty* d;
14438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 1 || sz == 2 || sz == 4);
14439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
14440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I32);
14441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d = unsafeIRDirty_1_N(
14442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             t2,
14443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             0/*regparms*/,
14444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             "x86g_dirtyhelper_IN",
14445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             &x86g_dirtyhelper_IN,
14446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkIRExprVec_2( mkexpr(t1), mkU32(sz) )
14447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
14448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* do the call, dumping the result in t2. */
14449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Dirty(d) );
14450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg(sz, R_EAX, narrowTo( ty, mkexpr(t2) ) );
14451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE6: /* OUT AL, imm8 */
14455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
14456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getIByte(delta); delta++;
14458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, mkU32( abyte & 0xFF ) );
14459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte);
14460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_OUT;
14461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE7: /* OUT eAX, imm8 */
14462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
14463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getIByte(delta); delta++;
14465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, mkU32( abyte & 0xFF ) );
14466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte);
14467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_OUT;
14468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xEE: /* OUT AL, %DX */
14469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
14470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          nameIReg(2,R_EDX));
14474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_OUT;
14475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xEF: /* OUT eAX, %DX */
14476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4);
14477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
14478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          nameIReg(2,R_EDX));
14481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_OUT;
14482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_OUT: {
14483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* At this point, sz indicates the width, and t1 is a 32-bit
14484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         value giving port number. */
14485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRDirty* d;
14486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 1 || sz == 2 || sz == 4);
14487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
14488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d = unsafeIRDirty_0_N(
14489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             0/*regparms*/,
14490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             "x86g_dirtyhelper_OUT",
14491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             &x86g_dirtyhelper_OUT,
14492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkIRExprVec_3( mkexpr(t1),
14493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            widenUto32( getIReg(sz, R_EAX) ),
14494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(sz) )
14495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
14496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Dirty(d) );
14497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp1 extensions) ---------- */
14501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x82: /* Grp1 Ib,Eb too.  Apparently this is the same as
14503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 case 0x80, but only in 32-bit mode. */
14504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fallthru */
14505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x80: /* Grp1 Ib,Eb */
14506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz    = 1;
14509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 1;
14510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = getUChar(delta + am_sz);
14511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
14512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x81: /* Grp1 Iv,Ev */
14515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = sz;
14518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = getUDisp(d_sz, delta + am_sz);
14519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
14520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x83: /* Grp1 Ib,Ev */
14523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 1;
14526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = getSDisp8(delta + am_sz);
14527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
14528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp2 extensions) ---------- */
14531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC0: { /* Grp2 Ib,Eb */
14533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 1;
14537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = getUChar(delta + am_sz);
14538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz    = 1;
14539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(d32 & 0xFF), NULL, &decode_OK );
14541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC1: { /* Grp2 Ib,Ev */
14546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 1;
14550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = getUChar(delta + am_sz);
14551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(d32 & 0xFF), NULL, &decode_OK );
14553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD0: { /* Grp2 1,Eb */
14558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 0;
14562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = 1;
14563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz    = 1;
14564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(d32), NULL, &decode_OK );
14566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD1: { /* Grp2 1,Ev */
14571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
14573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 0;
14575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d32   = 1;
14576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(d32), NULL, &decode_OK );
14578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD2: { /* Grp2 CL,Eb */
14583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
14585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 0;
14587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz    = 1;
14588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         getIReg(1,R_ECX), "%cl", &decode_OK );
14590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD3: { /* Grp2 CL,Ev */
14595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getIByte(delta);
14597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(delta);
14598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 0;
14599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         getIReg(1,R_ECX), "%cl", &decode_OK );
14601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp3 extensions) ---------- */
14607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF6: { /* Grp3 Eb */
14609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp3 ( sorb, pfx_lock, 1, delta, &decode_OK );
14611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF7: { /* Grp3 Ev */
14616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp3 ( sorb, pfx_lock, sz, delta, &decode_OK );
14618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp4 extensions) ---------- */
14624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xFE: { /* Grp4 Eb */
14626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp4 ( sorb, pfx_lock, delta, &decode_OK );
14628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp5 extensions) ---------- */
14634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xFF: { /* Grp5 Ev */
14636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
14637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp5 ( sorb, pfx_lock, sz, delta, &dres, &decode_OK );
14638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK)
14639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ Escapes to 2-byte opcodes -- */
14644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0F: {
14646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      opc = getIByte(delta); delta++;
14647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (opc) {
14648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
14650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBA: { /* Grp8 Ib,Ev */
14652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool decode_OK = False;
14653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
14654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         am_sz = lengthAMode(delta);
14655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32   = getSDisp8(delta + am_sz);
14656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_Grp8_Imm ( sorb, pfx_lock, delta, modrm,
14657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                am_sz, sz, d32, &decode_OK );
14658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!decode_OK)
14659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
14660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
14664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBC: /* BSF Gv,Ev */
14666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bs_E_G ( sorb, sz, delta, True );
14667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBD: /* BSR Gv,Ev */
14669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bs_E_G ( sorb, sz, delta, False );
14670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
14673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC8: /* BSWAP %eax */
14675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC9:
14676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCA:
14677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCB:
14678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCC:
14679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCD:
14680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCE:
14681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCF: /* BSWAP %edi */
14682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* AFAICS from the Intel docs, this only exists at size 4. */
14683663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         if (sz != 4) goto decode_failure;
14684663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
14685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I32);
14686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t1, getIReg(4, opc-0xC8) );
14687663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         t2 = math_BSWAP(t1, Ity_I32);
14688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, opc-0xC8, mkexpr(t2));
14690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
14691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
14694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA3: /* BT Gv,Ev */
14696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpNone );
14697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB3: /* BTR Gv,Ev */
14699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpReset );
14700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAB: /* BTS Gv,Ev */
14702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpSet );
14703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBB: /* BTC Gv,Ev */
14705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpComp );
14706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
14709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x40:
14711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x41:
14712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
14713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
14714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
14715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
14716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
14717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
14718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x48: /* CMOVSb (cmov negative) */
14719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x49: /* CMOVSb (cmov not negative) */
14720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4A: /* CMOVP (cmov parity even) */
14721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4B: /* CMOVNP (cmov parity odd) */
14722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
14723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
14724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
14725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
14726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
14727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
14730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB0: /* CMPXCHG Gb,Eb */
14732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_cmpxchg_G_E ( sorb, pfx_lock, 1, delta );
14733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB1: /* CMPXCHG Gv,Ev */
14735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_cmpxchg_G_E ( sorb, pfx_lock, sz, delta );
14736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC7: { /* CMPXCHG8B Gv (0F C7 /1) */
14739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp expdHi    = newTemp(Ity_I32);
14740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp expdLo    = newTemp(Ity_I32);
14741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp dataHi    = newTemp(Ity_I32);
14742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp dataLo    = newTemp(Ity_I32);
14743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldHi     = newTemp(Ity_I32);
14744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldLo     = newTemp(Ity_I32);
14745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp flags_old = newTemp(Ity_I32);
14746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp flags_new = newTemp(Ity_I32);
14747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp success   = newTemp(Ity_I1);
14748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Translate this using a DCAS, even if there is no LOCK
14750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            prefix.  Life is too short to bother with generating two
14751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            different translations for the with/without-LOCK-prefix
14752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            cases. */
14753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *expect_CAS = True;
14754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* Decode, and generate address. */
14756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4) goto decode_failure;
14757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
14758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) goto decode_failure;
14759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregOfRM(modrm) != 1) goto decode_failure;
14760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
14761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
14762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Get the expected and new values. */
14764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( expdHi, getIReg(4,R_EDX) );
14765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( expdLo, getIReg(4,R_EAX) );
14766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dataHi, getIReg(4,R_ECX) );
14767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dataLo, getIReg(4,R_EBX) );
14768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Do the DCAS */
14770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_CAS(
14771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkIRCAS( oldHi, oldLo,
14772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Iend_LE, mkexpr(addr),
14773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(expdHi), mkexpr(expdLo),
14774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(dataHi), mkexpr(dataLo)
14775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )));
14776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* success when oldHi:oldLo == expdHi:expdLo */
14778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( success,
14779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_CasCmpEQ32,
14780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Or32,
14781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Xor32, mkexpr(oldHi), mkexpr(expdHi)),
14782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Xor32, mkexpr(oldLo), mkexpr(expdLo))
14783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       ),
14784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(0)
14785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 ));
14786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If the DCAS is successful, that is to say oldHi:oldLo ==
14788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            expdHi:expdLo, then put expdHi:expdLo back in EDX:EAX,
14789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            which is where they came from originally.  Both the actual
14790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            contents of these two regs, and any shadow values, are
14791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unchanged.  If the DCAS fails then we're putting into
14792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            EDX:EAX the value seen in memory. */
14793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EDX,
14794436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    IRExpr_ITE( mkexpr(success),
14795436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                mkexpr(expdHi), mkexpr(oldHi)
14796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ));
14797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EAX,
14798436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    IRExpr_ITE( mkexpr(success),
14799436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                mkexpr(expdLo), mkexpr(oldLo)
14800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ));
14801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Copy the success bit into the Z flag and leave the others
14803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unchanged */
14804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( flags_old, widenUto32(mk_x86g_calculate_eflags_all()));
14805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(
14806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            flags_new,
14807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Or32,
14808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_And32, mkexpr(flags_old),
14809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU32(~X86G_CC_MASK_Z)),
14810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Shl32,
14811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And32,
14812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_1Uto32, mkexpr(success)), mkU32(1)),
14813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(X86G_CC_SHIFT_Z)) ));
14814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
14816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
14817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Set NDEP even though it isn't used.  This makes
14819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            redundant-PUT elimination of previous stores to this field
14820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            work better. */
14821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Sheesh.  Aren't you glad it was me and not you that had to
14824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    write and validate all this grunge? */
14825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 DIP("cmpxchg8b %s\n", dis_buf);
14827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 break;
14828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
14831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA2: { /* CPUID */
14833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Uses dirty helper:
14834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               void dirtyhelper_CPUID_sse[012] ( VexGuestX86State* )
14835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            declared to mod eax, wr ebx, ecx, edx
14836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
14837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRDirty* d     = NULL;
14838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         void*    fAddr = NULL;
14839436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         const HChar* fName = NULL;
14840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2) {
14841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fName = "x86g_dirtyhelper_CPUID_sse2";
14842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fAddr = &x86g_dirtyhelper_CPUID_sse2;
14843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
14845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE1) {
14846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fName = "x86g_dirtyhelper_CPUID_sse1";
14847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fAddr = &x86g_dirtyhelper_CPUID_sse1;
14848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
14850436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (archinfo->hwcaps & VEX_HWCAPS_X86_MMXEXT) {
14851436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            fName = "x86g_dirtyhelper_CPUID_mmxext";
14852436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            fAddr = &x86g_dirtyhelper_CPUID_mmxext;
14853436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         }
14854436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         else
14855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (archinfo->hwcaps == 0/*no SSE*/) {
14856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fName = "x86g_dirtyhelper_CPUID_sse0";
14857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fAddr = &x86g_dirtyhelper_CPUID_sse0;
14858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else
14859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("disInstr(x86)(cpuid)");
14860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(fName); vassert(fAddr);
14862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d = unsafeIRDirty_0_N ( 0/*regparms*/,
14863436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 fName, fAddr, mkIRExprVec_1(IRExpr_BBPTR()) );
14864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* declare guest state effects */
14865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->nFxState = 4;
14866663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vex_bzero(&d->fxState, sizeof(d->fxState));
14867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[0].fx     = Ifx_Modify;
14868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[0].offset = OFFB_EAX;
14869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[0].size   = 4;
14870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[1].fx     = Ifx_Write;
14871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[1].offset = OFFB_EBX;
14872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[1].size   = 4;
14873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[2].fx     = Ifx_Modify;
14874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[2].offset = OFFB_ECX;
14875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[2].size   = 4;
14876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[3].fx     = Ifx_Write;
14877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[3].offset = OFFB_EDX;
14878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[3].size   = 4;
14879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* execute the dirty call, side-effecting guest state */
14880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Dirty(d) );
14881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* CPUID is a serialising insn.  So, just in case someone is
14882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            using it as a memory fence ... */
14883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_MBE(Imbe_Fence) );
14884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cpuid\n");
14885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
14889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--             goto decode_failure;
14890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          t1 = newTemp(cb);
14892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          t2 = newTemp(cb);
14893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          t3 = newTemp(cb);
14894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          t4 = newTemp(cb);
14895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr0(cb, CALLM_S, 0);
14896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, GET,   4, ArchReg, R_EAX, TempReg, t1);
14898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, PUSH,  4, TempReg, t1);
14899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, MOV,   4, Literal, 0, TempReg, t2);
14901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uLiteral(cb, 0);
14902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, PUSH,  4, TempReg, t2);
14903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, MOV,   4, Literal, 0, TempReg, t3);
14905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uLiteral(cb, 0);
14906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, PUSH,  4, TempReg, t3);
14907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, MOV,   4, Literal, 0, TempReg, t4);
14909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uLiteral(cb, 0);
14910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, PUSH,  4, TempReg, t4);
14911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, CALLM, 0, Lit16,   VGOFF_(helper_CPUID));
14913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
14914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, POP,   4, TempReg, t4);
14916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, PUT,   4, TempReg, t4, ArchReg, R_EDX);
14917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, POP,   4, TempReg, t3);
14919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, PUT,   4, TempReg, t3, ArchReg, R_ECX);
14920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, POP,   4, TempReg, t2);
14922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, PUT,   4, TempReg, t2, ArchReg, R_EBX);
14923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr1(cb, POP,   4, TempReg, t1);
14925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, PUT,   4, TempReg, t1, ArchReg, R_EAX);
14926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr0(cb, CALLM_E, 0);
14928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          DIP("cpuid\n");
14929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          break;
14930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
14932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB6: /* MOVZXb Eb,Gv */
14934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 2 && sz != 4)
14935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
14936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_movx_E_G ( sorb, delta, 1, sz, False );
14937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB7: /* MOVZXw Ew,Gv */
14940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
14941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
14942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
14943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBE: /* MOVSXb Eb,Gv */
14946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 2 && sz != 4)
14947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
14948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_movx_E_G ( sorb, delta, 1, sz, True );
14949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBF: /* MOVSXw Ew,Gv */
14952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4 && /* accept movsww, sigh, see #250799 */sz != 2)
14953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
14954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_movx_E_G ( sorb, delta, 2, sz, True );
14955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
14958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--
14959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--       case 0xC3: /* MOVNTI Gv,Ev */
14960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          vg_assert(sz == 4);
14961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          modrm = getUChar(eip);
14962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          vg_assert(!epartIsReg(modrm));
14963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          t1 = newTemp(cb);
14964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
14965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          pair = disAMode ( cb, sorb, eip, dis_buf );
14966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          t2 = LOW24(pair);
14967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          eip += HI8(pair);
14968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
14969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
14970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--          break;
14971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
14973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAF: /* IMUL Ev, Gv */
14975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_mul_E_G ( sorb, sz, delta );
14976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
14979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x1F:
14981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
14982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) goto decode_failure;
14983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
14984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
14985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("nop%c %s\n", nameISize(sz), dis_buf);
14986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
14987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
14989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x80:
14990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x81:
14991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x82: /* JBb/JNAEb (jump below) */
14992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x83: /* JNBb/JAEb (jump not below) */
14993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x84: /* JZb/JEb (jump zero) */
14994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x85: /* JNZb/JNEb (jump not zero) */
14995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x86: /* JBEb/JNAb (jump below or equal) */
14996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x87: /* JNBEb/JAb (jump not below or equal) */
14997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x88: /* JSb (jump negative) */
14998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x89: /* JSb (jump not negative) */
14999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8A: /* JP (jump parity even) */
15000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8B: /* JNP/JPO (jump parity odd) */
15001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8C: /* JLb/JNGEb (jump less) */
15002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8D: /* JGEb/JNLb (jump greater or equal) */
15003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8E: /* JLEb/JNGb (jump less or equal) */
15004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8F: /* JGb/JNLEb (jump greater) */
15005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       { Int    jmpDelta;
15006436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         const HChar* comment  = "";
15007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         jmpDelta = (Int)getUDisp32(delta);
15008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32 = (((Addr32)guest_EIP_bbstart)+delta+4) + jmpDelta;
15009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4;
15010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (resteerCisOk
15011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && vex_control.guest_chase_cond
15012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && (Addr32)d32 != (Addr32)guest_EIP_bbstart
15013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && jmpDelta < 0
15014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
15015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Speculation: assume this backward branch is taken.  So
15016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               we need to emit a side-exit to the insn following this
15017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               one, on the negation of the condition, and continue at
15018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               the branch target address (d32).  If we wind up back at
15019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               the first instruction of the trace, just stop; it's
15020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               better to let the IR loop unroller handle that case.*/
15021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_Exit(
15022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mk_x86g_calculate_condition((X86Condcode)
15023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                 (1 ^ (opc - 0x80))),
15024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_Boring,
15025663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     IRConst_U32(guest_EIP_bbstart+delta),
15026663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     OFFB_EIP ) );
15027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext   = Dis_ResteerC;
15028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.continueAt = (Addr64)(Addr32)d32;
15029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            comment = "(assumed taken)";
15030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
15032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (resteerCisOk
15033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && vex_control.guest_chase_cond
15034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && (Addr32)d32 != (Addr32)guest_EIP_bbstart
15035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && jmpDelta >= 0
15036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && resteerOkFn( callback_opaque,
15037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             (Addr64)(Addr32)(guest_EIP_bbstart+delta)) ) {
15038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Speculation: assume this forward branch is not taken.
15039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               So we need to emit a side-exit to d32 (the dest) and
15040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               continue disassembling at the insn immediately
15041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               following this one. */
15042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_Exit(
15043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mk_x86g_calculate_condition((X86Condcode)(opc - 0x80)),
15044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_Boring,
15045663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     IRConst_U32(d32),
15046663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     OFFB_EIP ) );
15047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext   = Dis_ResteerC;
15048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.continueAt = (Addr64)(Addr32)(guest_EIP_bbstart+delta);
15049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            comment = "(assumed not taken)";
15050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else {
15052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Conservative default translation - end the block at
15053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               this point. */
15054663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            jcc_01( &dres, (X86Condcode)(opc - 0x80),
15055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    (Addr32)(guest_EIP_bbstart+delta), d32);
15056663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vassert(dres.whatNext == Dis_StopHere);
15057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("j%s-32 0x%x %s\n", name_X86Condcode(opc - 0x80), d32, comment);
15059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       }
15061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
15063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x31: { /* RDTSC */
15064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp   val  = newTemp(Ity_I64);
15065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr** args = mkIRExprVec_0();
15066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRDirty* d    = unsafeIRDirty_1_N (
15067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            val,
15068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            0/*regparms*/,
15069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            "x86g_dirtyhelper_RDTSC",
15070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            &x86g_dirtyhelper_RDTSC,
15071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            args
15072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         );
15073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* execute the dirty call, dumping the result in val. */
15074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Dirty(d) );
15075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EDX, unop(Iop_64HIto32, mkexpr(val)));
15076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg(4, R_EAX, unop(Iop_64to32, mkexpr(val)));
15077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("rdtsc\n");
15078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
15082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA1: /* POP %FS */
15084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_pop_segreg( R_FS, sz ); break;
15085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA9: /* POP %GS */
15086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_pop_segreg( R_GS, sz ); break;
15087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA0: /* PUSH %FS */
15089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_push_segreg( R_FS, sz ); break;
15090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA8: /* PUSH %GS */
15091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_push_segreg( R_GS, sz ); break;
15092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
15094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x90:
15095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x91:
15096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x92: /* set-Bb/set-NAEb (jump below) */
15097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x93: /* set-NBb/set-AEb (jump not below) */
15098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x94: /* set-Zb/set-Eb (jump zero) */
15099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x95: /* set-NZb/set-NEb (jump not zero) */
15100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x96: /* set-BEb/set-NAb (jump below or equal) */
15101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
15102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x98: /* set-Sb (jump negative) */
15103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x99: /* set-Sb (jump not negative) */
15104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9A: /* set-P (jump parity even) */
15105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9B: /* set-NP (jump parity odd) */
15106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9C: /* set-Lb/set-NGEb (jump less) */
15107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
15108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
15109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9F: /* set-Gb/set-NLEb (jump greater) */
15110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I8);
15111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
15112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
15113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
15114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
15115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg(1, eregOfRM(modrm), mkexpr(t1));
15116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("set%s %s\n", name_X86Condcode(opc-0x90),
15117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameIReg(1,eregOfRM(modrm)));
15118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
15119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           addr = disAMode ( &alen, sorb, delta, dis_buf );
15120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           delta += alen;
15121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           storeLE( mkexpr(addr), mkexpr(t1) );
15122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
15123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
15127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA4: /* SHLDv imm8,Gv,Ev */
15129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
15130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32   = delta + lengthAMode(delta);
15131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_sprintf(dis_buf, "$%d", getIByte(d32));
15132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_SHLRD_Gv_Ev (
15133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  sorb, delta, modrm, sz,
15134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU8(getIByte(d32)), True, /* literal */
15135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  dis_buf, True );
15136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA5: /* SHLDv %cl,Gv,Ev */
15138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
15139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_SHLRD_Gv_Ev (
15140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    sorb, delta, modrm, sz,
15141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getIReg(1,R_ECX), False, /* not literal */
15142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "%cl", True );
15143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAC: /* SHRDv imm8,Gv,Ev */
15146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
15147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d32   = delta + lengthAMode(delta);
15148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_sprintf(dis_buf, "$%d", getIByte(d32));
15149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_SHLRD_Gv_Ev (
15150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    sorb, delta, modrm, sz,
15151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(getIByte(d32)), True, /* literal */
15152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    dis_buf, False );
15153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAD: /* SHRDv %cl,Gv,Ev */
15155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getIByte(delta);
15156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_SHLRD_Gv_Ev (
15157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    sorb, delta, modrm, sz,
15158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getIReg(1,R_ECX), False, /* not literal */
15159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "%cl", False );
15160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- SYSENTER -=-=-=-=-=-=-=-=-=-= */
15163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x34:
15165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Simple implementation needing a long explaination.
15166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sysenter is a kind of syscall entry.  The key thing here
15168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            is that the return address is not known -- that is
15169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            something that is beyond Vex's knowledge.  So this IR
15170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            forces a return to the scheduler, which can do what it
15171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            likes to simulate the systenter, but it MUST set this
15172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            thread's guest_EIP field with the continuation address
15173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            before resuming execution.  If that doesn't happen, the
15174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            thread will jump to address zero, which is probably
15175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fatal.
15176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
15177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Note where we are, so we can back up the guest to this
15179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            point if the syscall needs to be restarted. */
15180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
15181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32(guest_EIP_curr_instr) ) );
15182663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         jmp_lit(&dres, Ijk_Sys_sysenter, 0/*bogus next EIP value*/);
15183663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(dres.whatNext == Dis_StopHere);
15184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("sysenter");
15185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
15188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC0: { /* XADD Gb,Eb */
15190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool decodeOK;
15191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_xadd_G_E ( sorb, pfx_lock, 1, delta, &decodeOK );
15192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!decodeOK) goto decode_failure;
15193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC1: { /* XADD Gv,Ev */
15196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool decodeOK;
15197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_xadd_G_E ( sorb, pfx_lock, sz, delta, &decodeOK );
15198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!decodeOK) goto decode_failure;
15199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
15203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x71:
15205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x72:
15206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
15207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
15209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
15210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
15211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
15212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFC:
15214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFD:
15215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
15216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEC:
15218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
15219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDC:
15221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
15222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF8:
15224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF9:
15225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
15226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE8:
15228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
15229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD8:
15231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
15232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
15234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
15235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
15237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x74:
15239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x75:
15240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
15241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x64:
15243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x65:
15244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
15245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
15247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
15248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
15249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x68:
15251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x69:
15252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
15253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x60:
15255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x61:
15256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
15257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
15259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
15260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
15261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
15262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
15264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF2:
15265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF3:
15266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
15268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD2:
15269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD3:
15270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
15272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE2:
15273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
15274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int  delta0    = delta-1;
15275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool decode_OK = False;
15276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If sz==2 this is SSE, and we assume sse idec has
15278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            already spotted those cases by now. */
15279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
15280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
15281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
15283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!decode_OK) {
15284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta = delta0;
15285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
15286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15290b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case 0x0E: /* FEMMS */
15291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x77: /* EMMS */
15292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
15293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
15294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_EMMS_preamble();
15295b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DIP("{f}emms\n");
15296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- SGDT and SIDT =-=-=-=-=-=-=-=-=-=-= */
15299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x01: /* 0F 01 /0 -- SGDT */
15300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 /* 0F 01 /1 -- SIDT */
15301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
15302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          /* This is really revolting, but ... since each processor
15303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (core) only has one IDT and one GDT, just let the guest
15304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             see it (pass-through semantics).  I can't see any way to
15305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             construct a faked-up value, so don't bother to try. */
15306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
15307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, sorb, delta, dis_buf );
15308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
15309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) goto decode_failure;
15310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)
15311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
15312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregOfRM(modrm)) {
15313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: DIP("sgdt %s\n", dis_buf); break;
15314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: DIP("sidt %s\n", dis_buf); break;
15315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0); /*NOTREACHED*/
15316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRDirty* d = unsafeIRDirty_0_N (
15319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          0/*regparms*/,
15320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "x86g_dirtyhelper_SxDT",
15321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          &x86g_dirtyhelper_SxDT,
15322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkIRExprVec_2( mkexpr(addr),
15323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU32(gregOfRM(modrm)) )
15324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      );
15325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* declare we're writing memory */
15326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->mFx   = Ifx_Write;
15327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->mAddr = mkexpr(addr);
15328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->mSize = 6;
15329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Dirty(d) );
15330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
15331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15333436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x05: /* AMD's syscall */
15334436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
15335436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov              mkU32(guest_EIP_curr_instr) ) );
15336436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         jmp_lit(&dres, Ijk_Sys_syscall, ((Addr32)guest_EIP_bbstart)+delta);
15337436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         vassert(dres.whatNext == Dis_StopHere);
15338436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         DIP("syscall\n");
15339436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
15340436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
15341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
15342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
15344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
15345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* switch (opc) for the 2-byte opcodes */
15346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   goto decode_success;
15347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* case 0x0F: of primary opcode */
15348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ ??? ------------------------ */
15350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  default:
15352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_failure:
15353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* All decode failures end up here. */
15354436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sigill_diag) {
15355436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vex_printf("vex x86->IR: unhandled instruction bytes: "
15356436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                 "0x%x 0x%x 0x%x 0x%x\n",
15357436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                 (Int)getIByte(delta_start+0),
15358436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                 (Int)getIByte(delta_start+1),
15359436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                 (Int)getIByte(delta_start+2),
15360436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                 (Int)getIByte(delta_start+3) );
15361436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
15362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Tell the dispatcher that this insn cannot be decoded, and so has
15364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      not been executed, and (is currently) the next to be executed.
15365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      EIP should be up-to-date since it made so at the start of each
15366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      insn, but nevertheless be paranoid and update it again right
15367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      now. */
15368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr) ) );
15369663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   jmp_lit(&dres, Ijk_NoDecode, guest_EIP_curr_instr);
15370663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vassert(dres.whatNext == Dis_StopHere);
15371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.len = 0;
15372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We also need to say that a CAS is not expected now, regardless
15373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of what it might have been set to at the start of the function,
15374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      since the IR that we've emitted just above (to synthesis a
15375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SIGILL) does not involve any CAS, and presumably no other IR has
15376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      been emitted for this (non-decoded) insn. */
15377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *expect_CAS = False;
15378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
15379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* switch (opc) for the main (primary) opcode switch. */
15381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_success:
15383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* All decode successes end up here. */
15384663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   switch (dres.whatNext) {
15385663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      case Dis_Continue:
15386663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_bbstart + delta) ) );
15387663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         break;
15388663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      case Dis_ResteerU:
15389663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      case Dis_ResteerC:
15390663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         stmt( IRStmt_Put( OFFB_EIP, mkU32(dres.continueAt) ) );
15391663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         break;
15392663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      case Dis_StopHere:
15393663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         break;
15394663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      default:
15395663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vassert(0);
15396663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
15397663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
15398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("\n");
15399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.len = delta - delta_start;
15400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
15401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
15402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef DIP
15404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef DIS
15405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
15408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Top-level fn                                         ---*/
15409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
15410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Disassemble a single instruction into IR.  The instruction
15412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is located in host memory at &guest_code[delta]. */
15413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownDisResult disInstr_X86 ( IRSB*        irsb_IN,
15415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Bool         (*resteerOkFn) ( void*, Addr64 ),
15416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Bool         resteerCisOk,
15417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         void*        callback_opaque,
15418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         UChar*       guest_code_IN,
15419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Long         delta,
15420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Addr64       guest_IP,
15421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         VexArch      guest_arch,
15422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         VexArchInfo* archinfo,
15423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         VexAbiInfo*  abiinfo,
15424436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         Bool         host_bigendian_IN,
15425436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         Bool         sigill_diag_IN )
15426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
15427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int       i, x1, x2;
15428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool      expect_CAS, has_CAS;
15429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DisResult dres;
15430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set globals (see top of this file) */
15432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guest_arch == VexArchX86);
15433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest_code           = guest_code_IN;
15434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   irsb                 = irsb_IN;
15435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   host_is_bigendian    = host_bigendian_IN;
15436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest_EIP_curr_instr = (Addr32)guest_IP;
15437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest_EIP_bbstart    = (Addr32)toUInt(guest_IP - delta);
15438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x1 = irsb_IN->stmts_used;
15440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   expect_CAS = False;
15441663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
15442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             resteerCisOk,
15443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             callback_opaque,
15444436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                             delta, archinfo, abiinfo, sigill_diag_IN );
15445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x2 = irsb_IN->stmts_used;
15446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(x2 >= x1);
15447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* See comment at the top of disInstr_X86_WRK for meaning of
15449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      expect_CAS.  Here, we (sanity-)check for the presence/absence of
15450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRCAS as directed by the returned expect_CAS value. */
15451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   has_CAS = False;
15452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = x1; i < x2; i++) {
15453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (irsb_IN->stmts[i]->tag == Ist_CAS)
15454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         has_CAS = True;
15455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (expect_CAS != has_CAS) {
15458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* inconsistency detected.  re-disassemble the instruction so as
15459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to generate a useful error message; then assert. */
15460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_traceflags |= VEX_TRACE_FE;
15461663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
15462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                resteerCisOk,
15463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                callback_opaque,
15464436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                delta, archinfo, abiinfo, sigill_diag_IN );
15465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = x1; i < x2; i++) {
15466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("\t\t");
15467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ppIRStmt(irsb_IN->stmts[i]);
15468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("\n");
15469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Failure of this assertion is serious and denotes a bug in
15471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         disInstr. */
15472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vpanic("disInstr_X86: inconsistency in LOCK prefix handling");
15473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
15476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
15477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
15480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                         guest_x86_toIR.c ---*/
15481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
15482