1c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
2c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*--------------------------------------------------------------------*/
3752f90673ebbb6b2f55fc5e46606dea371313713sewardj/*--- begin                                       guest_x86_toIR.c ---*/
4c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*--------------------------------------------------------------------*/
5c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
6f8ed9d874a7b8651654591c68c6d431c758d787csewardj/*
7752f90673ebbb6b2f55fc5e46606dea371313713sewardj   This file is part of Valgrind, a dynamic binary instrumentation
8752f90673ebbb6b2f55fc5e46606dea371313713sewardj   framework.
9f8ed9d874a7b8651654591c68c6d431c758d787csewardj
10ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   Copyright (C) 2004-2017 OpenWorks LLP
11752f90673ebbb6b2f55fc5e46606dea371313713sewardj      info@open-works.net
127bd6ffe203f3aa9e7b25f7eae40a9b9cf48710cfsewardj
13752f90673ebbb6b2f55fc5e46606dea371313713sewardj   This program is free software; you can redistribute it and/or
14752f90673ebbb6b2f55fc5e46606dea371313713sewardj   modify it under the terms of the GNU General Public License as
15752f90673ebbb6b2f55fc5e46606dea371313713sewardj   published by the Free Software Foundation; either version 2 of the
16752f90673ebbb6b2f55fc5e46606dea371313713sewardj   License, or (at your option) any later version.
177bd6ffe203f3aa9e7b25f7eae40a9b9cf48710cfsewardj
18752f90673ebbb6b2f55fc5e46606dea371313713sewardj   This program is distributed in the hope that it will be useful, but
19752f90673ebbb6b2f55fc5e46606dea371313713sewardj   WITHOUT ANY WARRANTY; without even the implied warranty of
20752f90673ebbb6b2f55fc5e46606dea371313713sewardj   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21752f90673ebbb6b2f55fc5e46606dea371313713sewardj   General Public License for more details.
22752f90673ebbb6b2f55fc5e46606dea371313713sewardj
23752f90673ebbb6b2f55fc5e46606dea371313713sewardj   You should have received a copy of the GNU General Public License
24752f90673ebbb6b2f55fc5e46606dea371313713sewardj   along with this program; if not, write to the Free Software
25752f90673ebbb6b2f55fc5e46606dea371313713sewardj   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
267bd6ffe203f3aa9e7b25f7eae40a9b9cf48710cfsewardj   02110-1301, USA.
277bd6ffe203f3aa9e7b25f7eae40a9b9cf48710cfsewardj
28752f90673ebbb6b2f55fc5e46606dea371313713sewardj   The GNU General Public License is contained in the file COPYING.
29f8ed9d874a7b8651654591c68c6d431c758d787csewardj
30f8ed9d874a7b8651654591c68c6d431c758d787csewardj   Neither the names of the U.S. Department of Energy nor the
31f8ed9d874a7b8651654591c68c6d431c758d787csewardj   University of California nor the names of its contributors may be
32f8ed9d874a7b8651654591c68c6d431c758d787csewardj   used to endorse or promote products derived from this software
33f8ed9d874a7b8651654591c68c6d431c758d787csewardj   without prior written permission.
34f8ed9d874a7b8651654591c68c6d431c758d787csewardj*/
35f8ed9d874a7b8651654591c68c6d431c758d787csewardj
36e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj/* Translates x86 code to IR. */
37e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
3877b86be374085943e902075b305ff047a053aac6sewardj/* TODO:
3945f1ff88fd124283a2f43e2167b07c039b4f4ecasewardj
403b3eacdfb862ea8571bec0018d2bc6ad7de5e328sewardj   All Puts to CC_OP/CC_DEP1/CC_DEP2/CC_NDEP should really be checked
413b3eacdfb862ea8571bec0018d2bc6ad7de5e328sewardj   to ensure a 32-bit value is being written.
423b3eacdfb862ea8571bec0018d2bc6ad7de5e328sewardj
43883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   FUCOMI(P): what happens to A and S flags?  Currently are forced
44883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      to zero.
453f61ddbfeb5ec1633b4ede7e4a057a7e77d9c9a4sewardj
46ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj   x87 FP Limitations:
47a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
48a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   * all arithmetic done at 64 bits
49a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
503f61ddbfeb5ec1633b4ede7e4a057a7e77d9c9a4sewardj   * no FP exceptions, except for handling stack over/underflow
51a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
523f61ddbfeb5ec1633b4ede7e4a057a7e77d9c9a4sewardj   * FP rounding mode observed only for float->int conversions
53a0e83b06f304527e3e9aec527c344e35e7023d76sewardj     and int->float conversions which could lose accuracy, and
54a0e83b06f304527e3e9aec527c344e35e7023d76sewardj     for float-to-float rounding.  For all other operations,
55a0e83b06f304527e3e9aec527c344e35e7023d76sewardj     round-to-nearest is used, regardless.
56a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
57e166ed089645c00ea80f732139c22ec2e2c402f1sewardj   * some of the FCOM cases could do with testing -- not convinced
58e166ed089645c00ea80f732139c22ec2e2c402f1sewardj     that the args are the right way round.
5952444cb6696efd612ced78daa8feb235808ef165sewardj
60a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   * FSAVE does not re-initialise the FPU; it should do
61a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
62a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   * FINIT not only initialises the FPU environment, it also
63a0e83b06f304527e3e9aec527c344e35e7023d76sewardj     zeroes all the FP registers.  It should leave the registers
64a0e83b06f304527e3e9aec527c344e35e7023d76sewardj     unchanged.
65a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
66cb2c99d61cb3e74fb461d03de40f9aea33a18901sewardj   SAHF should cause eflags[1] == 1, and in fact it produces 0.  As
67cb2c99d61cb3e74fb461d03de40f9aea33a18901sewardj   per Intel docs this bit has no meaning anyway.  Since PUSHF is the
68cb2c99d61cb3e74fb461d03de40f9aea33a18901sewardj   only way to observe eflags[1], a proper fix would be to make that
69cb2c99d61cb3e74fb461d03de40f9aea33a18901sewardj   bit be set by PUSHF.
70cb2c99d61cb3e74fb461d03de40f9aea33a18901sewardj
716d26984a0df6a7d20b658bac6edf869eb872cca3sewardj   The state of %eflags.AC (alignment check, bit 18) is recorded by
726d26984a0df6a7d20b658bac6edf869eb872cca3sewardj   the simulation (viz, if you set it with popf then a pushf produces
736d26984a0df6a7d20b658bac6edf869eb872cca3sewardj   the value you set it to), but it is otherwise ignored.  In
746d26984a0df6a7d20b658bac6edf869eb872cca3sewardj   particular, setting it to 1 does NOT cause alignment checking to
756d26984a0df6a7d20b658bac6edf869eb872cca3sewardj   happen.  Programs that set it to 1 and then rely on the resulting
766d26984a0df6a7d20b658bac6edf869eb872cca3sewardj   SIGBUSs to inform them of misaligned accesses will not work.
776d26984a0df6a7d20b658bac6edf869eb872cca3sewardj
78e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   Implementation of sysenter is necessarily partial.  sysenter is a
79e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   kind of system call entry.  When doing a sysenter, the return
80e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   address is not known -- that is something that is beyond Vex's
81e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   knowledge.  So the generated IR forces a return to the scheduler,
82e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   which can do what it likes to simulate the systenter, but it MUST
83e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   set this thread's guest_EIP field with the continuation address
84e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   before resuming execution.  If that doesn't happen, the thread will
85e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   jump to address zero, which is probably fatal.
86f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj
8752444cb6696efd612ced78daa8feb235808ef165sewardj   This module uses global variables and so is not MT-safe (if that
88e395ae8fd8c87eeafc7100a0b5c8f8bb7bee8055sewardj   should ever become relevant).
89e395ae8fd8c87eeafc7100a0b5c8f8bb7bee8055sewardj
90e395ae8fd8c87eeafc7100a0b5c8f8bb7bee8055sewardj   The delta values are 32-bit ints, not 64-bit ints.  That means
91e395ae8fd8c87eeafc7100a0b5c8f8bb7bee8055sewardj   this module may not work right if run on a 64-bit host.  That should
92e395ae8fd8c87eeafc7100a0b5c8f8bb7bee8055sewardj   be fixed properly, really -- if anyone ever wants to use Vex to
93e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   translate x86 code for execution on a 64-bit host.
94e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
95e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   casLE (implementation of lock-prefixed insns) and rep-prefixed
96e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   insns: the side-exit back to the start of the insn is done with
97e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   Ijk_Boring.  This is quite wrong, it should be done with
98e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   Ijk_NoRedir, since otherwise the side exit, which is intended to
99e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   restart the instruction for whatever reason, could go somewhere
100e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   entirely else.  Doing it right (with Ijk_NoRedir jumps) would make
101e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   no-redir jumps performance critical, at least for rep-prefixed
102e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   instructions, since all iterations thereof would involve such a
103e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   jump.  It's not such a big deal with casLE since the side exit is
104e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   only taken if the CAS fails, that is, the location is contended,
105e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   which is relatively unlikely.
1061fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj
1076c299f3acab617581ea504e45fbb6cab24c2b29fsewardj   XXXX: Nov 2009: handling of SWP on ARM suffers from the same
1086c299f3acab617581ea504e45fbb6cab24c2b29fsewardj   problem.
1096c299f3acab617581ea504e45fbb6cab24c2b29fsewardj
1101fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj   Note also, the test for CAS success vs failure is done using
1111fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj   Iop_CasCmp{EQ,NE}{8,16,32,64} rather than the ordinary
1121fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj   Iop_Cmp{EQ,NE} equivalents.  This is so as to tell Memcheck that it
1131fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj   shouldn't definedness-check these comparisons.  See
1141fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj   COMMENT_ON_CasCmpEQ in memcheck/mc_translate.c for
1151fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj   background/rationale.
116e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj*/
117e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1189f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj/* Performance holes:
1199f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj
1209f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj   - fcom ; fstsw %ax ; sahf
1219f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj     sahf does not update the O flag (sigh) and so O needs to
1229f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj     be computed.  This is done expensively; it would be better
1239f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj     to have a calculate_eflags_o helper.
1249f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj
1259f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj   - emwarns; some FP codes can generate huge numbers of these
1269f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj     if the fpucw is changed in an inner loop.  It would be
1279f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj     better for the guest state to have an emwarn-enable reg
1289f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj     which can be set zero or nonzero.  If it is zero, emwarns
1299f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj     are not flagged, and instead control just flows all the
1309f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj     way through bbs as usual.
1319f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj*/
1329f8a3951d05b9369966b0ea09a62caeae5ba4e0fsewardj
133ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj/* "Special" instructions.
134ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj
135ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   This instruction decoder can decode three special instructions
136ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   which mean nothing natively (are no-ops as far as regs/mem are
137ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   concerned) but have meaning for supporting Valgrind.  A special
138ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   instruction is flagged by the 12-byte preamble C1C703 C1C70D C1C71D
139ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   C1C713 (in the standard interpretation, that means: roll $3, %edi;
140ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   roll $13, %edi; roll $29, %edi; roll $19, %edi).  Following that,
141ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   one of the following 3 are allowed (standard interpretation in
142ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   parentheses):
143ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj
144ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj      87DB (xchgl %ebx,%ebx)   %EDX = client_request ( %EAX )
145ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj      87C9 (xchgl %ecx,%ecx)   %EAX = guest_NRADDR
146ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj      87D2 (xchgl %edx,%edx)   call-noredir *%EAX
1472245ce9e834193d49261b8a433b4a0bd128c878eflorian      87FF (xchgl %edi,%edi)   IR injection
148ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj
149ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   Any other bytes following the 12-byte preamble are illegal and
150ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   constitute a failure in instruction decoding.  This all assumes
151ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   that the preamble will never occur except in specific code
152ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   fragments designed for Valgrind to catch.
153ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj
154ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   No prefixes may precede a "Special" instruction.
155ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj*/
156ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj
157e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj/* LOCK prefixed instructions.  These are translated using IR-level
158e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   CAS statements (IRCAS) and are believed to preserve atomicity, even
159e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   from the point of view of some other process racing against a
160e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   simulated one (presumably they communicate via a shared memory
161e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   segment).
162e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
163e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   Handlers which are aware of LOCK prefixes are:
164e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      dis_op2_G_E      (add, or, adc, sbb, and, sub, xor)
165e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      dis_cmpxchg_G_E  (cmpxchg)
166e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      dis_Grp1         (add, or, adc, sbb, and, sub, xor)
167e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      dis_Grp3         (not, neg)
168e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      dis_Grp4         (inc, dec)
169e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      dis_Grp5         (inc, dec)
170e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      dis_Grp8_Imm     (bts, btc, btr)
171e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      dis_bt_G_E       (bts, btc, btr)
172e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      dis_xadd_G_E     (xadd)
173e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj*/
174ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj
175c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
176c9a6570e86f4252f8a486b4df48de8710d357a4asewardj#include "libvex_basictypes.h"
177c9a6570e86f4252f8a486b4df48de8710d357a4asewardj#include "libvex_ir.h"
178e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj#include "libvex.h"
179f6dc3ce7df8154569748530c20b31c44f60ab6f8sewardj#include "libvex_guest_x86.h"
180c0ee2edb4563c90bc8f1a83a09984a1fda86d1d3sewardj
181cef7d3e3df4796e35b4521158d9dc058f034aa87sewardj#include "main_util.h"
182cef7d3e3df4796e35b4521158d9dc058f034aa87sewardj#include "main_globals.h"
183cef7d3e3df4796e35b4521158d9dc058f034aa87sewardj#include "guest_generic_bb_to_IR.h"
184cef7d3e3df4796e35b4521158d9dc058f034aa87sewardj#include "guest_generic_x87.h"
185cef7d3e3df4796e35b4521158d9dc058f034aa87sewardj#include "guest_x86_defs.h"
186c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
187c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
188c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*------------------------------------------------------------*/
189c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*--- Globals                                              ---*/
190c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*------------------------------------------------------------*/
191c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
1929e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj/* These are set at the start of the translation of an insn, right
1939e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   down in disInstr_X86, so that we don't have to pass them around
1949e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   endlessly.  They are all constant during the translation of any
1959e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   given insn. */
196c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
197c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/* We need to know this to do sub-register accesses correctly. */
1989b76916dcc1628e133d57db001563429c6e3a590sewardjstatic VexEndness host_endness;
199c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
2009e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj/* Pointer to the guest code area (points to start of BB, not to the
2019e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   insn being processed). */
2028462d113e3efeacceb304222dada8d85f748295aflorianstatic const UChar* guest_code;
203c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
204c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/* The guest address corresponding to guest_code[0]. */
2059e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardjstatic Addr32 guest_EIP_bbstart;
206c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
20752444cb6696efd612ced78daa8feb235808ef165sewardj/* The guest address for the instruction currently being
20852444cb6696efd612ced78daa8feb235808ef165sewardj   translated. */
2099e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardjstatic Addr32 guest_EIP_curr_instr;
21052444cb6696efd612ced78daa8feb235808ef165sewardj
211dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj/* The IRSB* into which we're generating code. */
212dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardjstatic IRSB* irsb;
213c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
214c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
215c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*------------------------------------------------------------*/
216c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*--- Debugging output                                     ---*/
217c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*------------------------------------------------------------*/
218c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
219f48ac19a67a98af44fe452c8c2be4192ac94b62dsewardj#define DIP(format, args...)           \
2209e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   if (vex_traceflags & VEX_TRACE_FE)  \
221c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      vex_printf(format, ## args)
222c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
223f48ac19a67a98af44fe452c8c2be4192ac94b62dsewardj#define DIS(buf, format, args...)      \
2249e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   if (vex_traceflags & VEX_TRACE_FE)  \
225c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      vex_sprintf(buf, format, ## args)
226c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
227c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
228c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*------------------------------------------------------------*/
229dcc85fccd114ba8a4fc1da11a0ca5c7f01e96fe6sewardj/*--- Offsets of various parts of the x86 guest state.     ---*/
230dcc85fccd114ba8a4fc1da11a0ca5c7f01e96fe6sewardj/*------------------------------------------------------------*/
231dcc85fccd114ba8a4fc1da11a0ca5c7f01e96fe6sewardj
232c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_EAX       offsetof(VexGuestX86State,guest_EAX)
233c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_EBX       offsetof(VexGuestX86State,guest_EBX)
234c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_ECX       offsetof(VexGuestX86State,guest_ECX)
235c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_EDX       offsetof(VexGuestX86State,guest_EDX)
236c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_ESP       offsetof(VexGuestX86State,guest_ESP)
237c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_EBP       offsetof(VexGuestX86State,guest_EBP)
238c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_ESI       offsetof(VexGuestX86State,guest_ESI)
239c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_EDI       offsetof(VexGuestX86State,guest_EDI)
240c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
241c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_EIP       offsetof(VexGuestX86State,guest_EIP)
242c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
243c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_CC_OP     offsetof(VexGuestX86State,guest_CC_OP)
244c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_CC_DEP1   offsetof(VexGuestX86State,guest_CC_DEP1)
245c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_CC_DEP2   offsetof(VexGuestX86State,guest_CC_DEP2)
246c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_CC_NDEP   offsetof(VexGuestX86State,guest_CC_NDEP)
247c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
248c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_FPREGS    offsetof(VexGuestX86State,guest_FPREG[0])
249c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_FPTAGS    offsetof(VexGuestX86State,guest_FPTAG[0])
250c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_DFLAG     offsetof(VexGuestX86State,guest_DFLAG)
251c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_IDFLAG    offsetof(VexGuestX86State,guest_IDFLAG)
2526d26984a0df6a7d20b658bac6edf869eb872cca3sewardj#define OFFB_ACFLAG    offsetof(VexGuestX86State,guest_ACFLAG)
253c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_FTOP      offsetof(VexGuestX86State,guest_FTOP)
254c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_FC3210    offsetof(VexGuestX86State,guest_FC3210)
255c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_FPROUND   offsetof(VexGuestX86State,guest_FPROUND)
256c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
257c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_CS        offsetof(VexGuestX86State,guest_CS)
258c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_DS        offsetof(VexGuestX86State,guest_DS)
259c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_ES        offsetof(VexGuestX86State,guest_ES)
260c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_FS        offsetof(VexGuestX86State,guest_FS)
261c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_GS        offsetof(VexGuestX86State,guest_GS)
262c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_SS        offsetof(VexGuestX86State,guest_SS)
2633bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj#define OFFB_LDT       offsetof(VexGuestX86State,guest_LDT)
2643bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj#define OFFB_GDT       offsetof(VexGuestX86State,guest_GDT)
265c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
266c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_SSEROUND  offsetof(VexGuestX86State,guest_SSEROUND)
267c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_XMM0      offsetof(VexGuestX86State,guest_XMM0)
268c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_XMM1      offsetof(VexGuestX86State,guest_XMM1)
269c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_XMM2      offsetof(VexGuestX86State,guest_XMM2)
270c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_XMM3      offsetof(VexGuestX86State,guest_XMM3)
271c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_XMM4      offsetof(VexGuestX86State,guest_XMM4)
272c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_XMM5      offsetof(VexGuestX86State,guest_XMM5)
273c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_XMM6      offsetof(VexGuestX86State,guest_XMM6)
274c9a43665879a03886b27a65b68af2a2c11b04f59sewardj#define OFFB_XMM7      offsetof(VexGuestX86State,guest_XMM7)
275c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
2766ef84bed9bb3af22060eb1759788034602bbcc88florian#define OFFB_EMNOTE    offsetof(VexGuestX86State,guest_EMNOTE)
277dcc85fccd114ba8a4fc1da11a0ca5c7f01e96fe6sewardj
27805f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj#define OFFB_CMSTART   offsetof(VexGuestX86State,guest_CMSTART)
27905f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj#define OFFB_CMLEN     offsetof(VexGuestX86State,guest_CMLEN)
280ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj#define OFFB_NRADDR    offsetof(VexGuestX86State,guest_NRADDR)
281ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj
282e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj#define OFFB_IP_AT_SYSCALL offsetof(VexGuestX86State,guest_IP_AT_SYSCALL)
283e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj
284dcc85fccd114ba8a4fc1da11a0ca5c7f01e96fe6sewardj
285dcc85fccd114ba8a4fc1da11a0ca5c7f01e96fe6sewardj/*------------------------------------------------------------*/
286c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*--- Helper bits and pieces for deconstructing the        ---*/
287c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*--- x86 insn stream.                                     ---*/
288c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*------------------------------------------------------------*/
289c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
290d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/* This is the Intel register encoding -- integer regs. */
291d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj#define R_EAX 0
292d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj#define R_ECX 1
293d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj#define R_EDX 2
294d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj#define R_EBX 3
295d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj#define R_ESP 4
296d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj#define R_EBP 5
297d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj#define R_ESI 6
298d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj#define R_EDI 7
299d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
3004e82db7b7141106436f7f543c30050f80fcc9933sewardj#define R_AL (0+R_EAX)
3014e82db7b7141106436f7f543c30050f80fcc9933sewardj#define R_AH (4+R_EAX)
3024e82db7b7141106436f7f543c30050f80fcc9933sewardj
303063f02f7e77ca024d24786bec402ca296a05bd6esewardj/* This is the Intel register encoding -- segment regs. */
304063f02f7e77ca024d24786bec402ca296a05bd6esewardj#define R_ES 0
305063f02f7e77ca024d24786bec402ca296a05bd6esewardj#define R_CS 1
306063f02f7e77ca024d24786bec402ca296a05bd6esewardj#define R_SS 2
307063f02f7e77ca024d24786bec402ca296a05bd6esewardj#define R_DS 3
308063f02f7e77ca024d24786bec402ca296a05bd6esewardj#define R_FS 4
309063f02f7e77ca024d24786bec402ca296a05bd6esewardj#define R_GS 5
310063f02f7e77ca024d24786bec402ca296a05bd6esewardj
311d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
312ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj/* Add a statement to the list held by "irbb". */
313ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardjstatic void stmt ( IRStmt* st )
314ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj{
315dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   addStmtToIRSB( irsb, st );
316ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj}
317ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj
318ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj/* Generate a new temporary of the given type. */
319ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardjstatic IRTemp newTemp ( IRType ty )
320ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj{
321496a58d130a28ac3a5ba33c9012dabbe61dc852csewardj   vassert(isPlausibleIRType(ty));
322dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   return newIRTemp( irsb->tyenv, ty );
323ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj}
324ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj
325ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj/* Various simple conversions */
326ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj
327e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjstatic UInt extend_s_8to32( UInt x )
328d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
329108e03fcb0a4ef42164235b1988aa540aa1e5298florian   return (UInt)((Int)(x << 24) >> 24);
330d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
331d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
3320611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardjstatic UInt extend_s_16to32 ( UInt x )
3330611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj{
334108e03fcb0a4ef42164235b1988aa540aa1e5298florian  return (UInt)((Int)(x << 16) >> 16);
3350611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj}
3360611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
337d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/* Fetch a byte from the guest insn stream. */
33852d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UChar getIByte ( Int delta )
339d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
340d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   return guest_code[delta];
341d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
342d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
343c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/* Extract the reg field from a modRM byte. */
344e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjstatic Int gregOfRM ( UChar mod_reg_rm )
345c9a6570e86f4252f8a486b4df48de8710d357a4asewardj{
346c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   return (Int)( (mod_reg_rm >> 3) & 7 );
347c9a6570e86f4252f8a486b4df48de8710d357a4asewardj}
348c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
349c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/* Figure out whether the mod and rm parts of a modRM byte refer to a
350c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   register or memory.  If so, the byte will have the form 11XXXYYY,
351c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   where YYY is the register number. */
352e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjstatic Bool epartIsReg ( UChar mod_reg_rm )
353c9a6570e86f4252f8a486b4df48de8710d357a4asewardj{
3542d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj   return toBool(0xC0 == (mod_reg_rm & 0xC0));
355c9a6570e86f4252f8a486b4df48de8710d357a4asewardj}
356c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
357c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/* ... and extract the register number ... */
358e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjstatic Int eregOfRM ( UChar mod_reg_rm )
359c9a6570e86f4252f8a486b4df48de8710d357a4asewardj{
360c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   return (Int)(mod_reg_rm & 0x7);
361c9a6570e86f4252f8a486b4df48de8710d357a4asewardj}
362c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
363e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj/* Get a 8/16/32-bit unsigned value out of the insn stream. */
364e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
36552d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UChar getUChar ( Int delta )
366e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj{
3672d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj   UChar v = guest_code[delta+0];
3689b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj   return toUChar(v);
369e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj}
370e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
37152d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt getUDisp16 ( Int delta )
372e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj{
373e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   UInt v = guest_code[delta+1]; v <<= 8;
374e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   v |= guest_code[delta+0];
375e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   return v & 0xFFFF;
376e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj}
377e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
37852d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt getUDisp32 ( Int delta )
379d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
380d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   UInt v = guest_code[delta+3]; v <<= 8;
381d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   v |= guest_code[delta+2]; v <<= 8;
382d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   v |= guest_code[delta+1]; v <<= 8;
383d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   v |= guest_code[delta+0];
384d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   return v;
385d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
386d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
38752d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt getUDisp ( Int size, Int delta )
388e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj{
389e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   switch (size) {
390e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      case 4: return getUDisp32(delta);
391e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      case 2: return getUDisp16(delta);
3922d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      case 1: return (UInt)getUChar(delta);
393e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      default: vpanic("getUDisp(x86)");
394e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   }
395e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   return 0; /*notreached*/
396e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj}
397e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
398e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
399d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/* Get a byte value out of the insn stream and sign-extend to 32
400d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   bits. */
40152d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt getSDisp8 ( Int delta )
402d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
403d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   return extend_s_8to32( (UInt) (guest_code[delta]) );
404d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
405d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
40652d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt getSDisp16 ( Int delta0 )
4070611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj{
4088462d113e3efeacceb304222dada8d85f748295aflorian   const UChar* eip = &guest_code[delta0];
4090611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   UInt d = *eip++;
4100611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   d |= ((*eip++) << 8);
4110611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   return extend_s_16to32(d);
4120611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj}
4130611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
41452d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt getSDisp ( Int size, Int delta )
4150611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj{
4160611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   switch (size) {
4170611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      case 4: return getUDisp32(delta);
4180611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      case 2: return getSDisp16(delta);
4190611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      case 1: return getSDisp8(delta);
4200611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      default: vpanic("getSDisp(x86)");
4210611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj  }
4220611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj  return 0; /*notreached*/
4230611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj}
424d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
425c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
426c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*------------------------------------------------------------*/
427c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*--- Helpers for constructing IR.                         ---*/
428c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*------------------------------------------------------------*/
429c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
430c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/* Create a 1/2/4 byte read of an x86 integer registers.  For 16/8 bit
431c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   register references, we need to take the host endianness into
432c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   account.  Supplied value is 0 .. 7 and in the Intel instruction
433c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   encoding. */
434e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
4359334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardjstatic IRType szToITy ( Int n )
4369334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj{
4379334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   switch (n) {
4389334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      case 1: return Ity_I8;
4399334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      case 2: return Ity_I16;
4409334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      case 4: return Ity_I32;
4419334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      default: vpanic("szToITy(x86)");
4429334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   }
4439334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj}
4449334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
44567e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj/* On a little-endian host, less significant bits of the guest
44667e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   registers are at lower addresses.  Therefore, if a reference to a
44767e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   register low half has the safe guest state offset as a reference to
44867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   the full register.
44967e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj*/
4509334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardjstatic Int integerGuestRegOffset ( Int sz, UInt archreg )
451c9a6570e86f4252f8a486b4df48de8710d357a4asewardj{
452c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   vassert(archreg < 8);
453c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
4549334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   /* Correct for little-endian host only. */
4559b76916dcc1628e133d57db001563429c6e3a590sewardj   vassert(host_endness == VexEndnessLE);
456063f02f7e77ca024d24786bec402ca296a05bd6esewardj
457063f02f7e77ca024d24786bec402ca296a05bd6esewardj   if (sz == 4 || sz == 2 || (sz == 1 && archreg < 4)) {
458063f02f7e77ca024d24786bec402ca296a05bd6esewardj      switch (archreg) {
459c9a43665879a03886b27a65b68af2a2c11b04f59sewardj         case R_EAX: return OFFB_EAX;
460c9a43665879a03886b27a65b68af2a2c11b04f59sewardj         case R_EBX: return OFFB_EBX;
461c9a43665879a03886b27a65b68af2a2c11b04f59sewardj         case R_ECX: return OFFB_ECX;
462c9a43665879a03886b27a65b68af2a2c11b04f59sewardj         case R_EDX: return OFFB_EDX;
463c9a43665879a03886b27a65b68af2a2c11b04f59sewardj         case R_ESI: return OFFB_ESI;
464c9a43665879a03886b27a65b68af2a2c11b04f59sewardj         case R_EDI: return OFFB_EDI;
465c9a43665879a03886b27a65b68af2a2c11b04f59sewardj         case R_ESP: return OFFB_ESP;
466c9a43665879a03886b27a65b68af2a2c11b04f59sewardj         case R_EBP: return OFFB_EBP;
467063f02f7e77ca024d24786bec402ca296a05bd6esewardj         default: vpanic("integerGuestRegOffset(x86,le)(4,2)");
468063f02f7e77ca024d24786bec402ca296a05bd6esewardj      }
469063f02f7e77ca024d24786bec402ca296a05bd6esewardj   }
470063f02f7e77ca024d24786bec402ca296a05bd6esewardj
471063f02f7e77ca024d24786bec402ca296a05bd6esewardj   vassert(archreg >= 4 && archreg < 8 && sz == 1);
472063f02f7e77ca024d24786bec402ca296a05bd6esewardj   switch (archreg-4) {
473c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case R_EAX: return 1+ OFFB_EAX;
474c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case R_EBX: return 1+ OFFB_EBX;
475c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case R_ECX: return 1+ OFFB_ECX;
476c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case R_EDX: return 1+ OFFB_EDX;
477063f02f7e77ca024d24786bec402ca296a05bd6esewardj      default: vpanic("integerGuestRegOffset(x86,le)(1h)");
478063f02f7e77ca024d24786bec402ca296a05bd6esewardj   }
479063f02f7e77ca024d24786bec402ca296a05bd6esewardj
480063f02f7e77ca024d24786bec402ca296a05bd6esewardj   /* NOTREACHED */
481063f02f7e77ca024d24786bec402ca296a05bd6esewardj   vpanic("integerGuestRegOffset(x86,le)");
482063f02f7e77ca024d24786bec402ca296a05bd6esewardj}
483063f02f7e77ca024d24786bec402ca296a05bd6esewardj
484063f02f7e77ca024d24786bec402ca296a05bd6esewardjstatic Int segmentGuestRegOffset ( UInt sreg )
485063f02f7e77ca024d24786bec402ca296a05bd6esewardj{
486063f02f7e77ca024d24786bec402ca296a05bd6esewardj   switch (sreg) {
487c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case R_ES: return OFFB_ES;
488c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case R_CS: return OFFB_CS;
489c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case R_SS: return OFFB_SS;
490c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case R_DS: return OFFB_DS;
491c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case R_FS: return OFFB_FS;
492c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case R_GS: return OFFB_GS;
493063f02f7e77ca024d24786bec402ca296a05bd6esewardj      default: vpanic("segmentGuestRegOffset(x86)");
4949334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   }
4959334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj}
4969334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
497c9a43665879a03886b27a65b68af2a2c11b04f59sewardjstatic Int xmmGuestRegOffset ( UInt xmmreg )
498c9a43665879a03886b27a65b68af2a2c11b04f59sewardj{
499c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   switch (xmmreg) {
500c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case 0: return OFFB_XMM0;
501c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case 1: return OFFB_XMM1;
502c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case 2: return OFFB_XMM2;
503c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case 3: return OFFB_XMM3;
504c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case 4: return OFFB_XMM4;
505c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case 5: return OFFB_XMM5;
506c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case 6: return OFFB_XMM6;
507c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      case 7: return OFFB_XMM7;
508c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      default: vpanic("xmmGuestRegOffset");
509c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   }
510c9a43665879a03886b27a65b68af2a2c11b04f59sewardj}
511c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
51267e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj/* Lanes of vector registers are always numbered from zero being the
51367e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   least significant lane (rightmost in the register).  */
51467e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj
515e5854d6d470f21677ec84f71d09129434b044246sewardjstatic Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
516e5854d6d470f21677ec84f71d09129434b044246sewardj{
517e5854d6d470f21677ec84f71d09129434b044246sewardj   /* Correct for little-endian host only. */
5189b76916dcc1628e133d57db001563429c6e3a590sewardj   vassert(host_endness == VexEndnessLE);
519e5854d6d470f21677ec84f71d09129434b044246sewardj   vassert(laneno >= 0 && laneno < 8);
520e5854d6d470f21677ec84f71d09129434b044246sewardj   return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
521e5854d6d470f21677ec84f71d09129434b044246sewardj}
522e5854d6d470f21677ec84f71d09129434b044246sewardj
52367e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardjstatic Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
52467e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj{
52567e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   /* Correct for little-endian host only. */
5269b76916dcc1628e133d57db001563429c6e3a590sewardj   vassert(host_endness == VexEndnessLE);
52767e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   vassert(laneno >= 0 && laneno < 4);
52867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
52967e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj}
53067e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj
53167e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardjstatic Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
53267e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj{
53367e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   /* Correct for little-endian host only. */
5349b76916dcc1628e133d57db001563429c6e3a590sewardj   vassert(host_endness == VexEndnessLE);
53567e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   vassert(laneno >= 0 && laneno < 2);
53667e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
53767e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj}
53867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj
5399334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardjstatic IRExpr* getIReg ( Int sz, UInt archreg )
5409334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj{
5419334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   vassert(sz == 1 || sz == 2 || sz == 4);
5429334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   vassert(archreg < 8);
5439334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   return IRExpr_Get( integerGuestRegOffset(sz,archreg),
5445bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                      szToITy(sz) );
545c9a6570e86f4252f8a486b4df48de8710d357a4asewardj}
546c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
547c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/* Ditto, but write to a reg instead. */
54841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardjstatic void putIReg ( Int sz, UInt archreg, IRExpr* e )
549c9a6570e86f4252f8a486b4df48de8710d357a4asewardj{
550dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRType ty = typeOfIRExpr(irsb->tyenv, e);
551d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj   switch (sz) {
552d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj      case 1: vassert(ty == Ity_I8); break;
553d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj      case 2: vassert(ty == Ity_I16); break;
554d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj      case 4: vassert(ty == Ity_I32); break;
555d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj      default: vpanic("putIReg(x86)");
556d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj   }
557c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   vassert(archreg < 8);
558eeb9ef8549a9c4aa15cbfbda52e20703d778fc61sewardj   stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
559d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
560d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
561063f02f7e77ca024d24786bec402ca296a05bd6esewardjstatic IRExpr* getSReg ( UInt sreg )
562063f02f7e77ca024d24786bec402ca296a05bd6esewardj{
563063f02f7e77ca024d24786bec402ca296a05bd6esewardj   return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
564063f02f7e77ca024d24786bec402ca296a05bd6esewardj}
565063f02f7e77ca024d24786bec402ca296a05bd6esewardj
566063f02f7e77ca024d24786bec402ca296a05bd6esewardjstatic void putSReg ( UInt sreg, IRExpr* e )
567063f02f7e77ca024d24786bec402ca296a05bd6esewardj{
568dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
569063f02f7e77ca024d24786bec402ca296a05bd6esewardj   stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
570063f02f7e77ca024d24786bec402ca296a05bd6esewardj}
571063f02f7e77ca024d24786bec402ca296a05bd6esewardj
572c9a43665879a03886b27a65b68af2a2c11b04f59sewardjstatic IRExpr* getXMMReg ( UInt xmmreg )
573c9a43665879a03886b27a65b68af2a2c11b04f59sewardj{
574c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
575c9a43665879a03886b27a65b68af2a2c11b04f59sewardj}
576c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
57767e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardjstatic IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
57867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj{
57967e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
58067e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj}
58167e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj
582fd22645d1e2445a568dda9ae665bd3a1315dea58sewardjstatic IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
58367e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj{
584fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
58567e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj}
58667e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj
5879636b44102bd3f79cba764576f34931d7b584d9esewardjstatic IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
5889636b44102bd3f79cba764576f34931d7b584d9esewardj{
5899636b44102bd3f79cba764576f34931d7b584d9esewardj   return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
5909636b44102bd3f79cba764576f34931d7b584d9esewardj}
5919636b44102bd3f79cba764576f34931d7b584d9esewardj
592fd22645d1e2445a568dda9ae665bd3a1315dea58sewardjstatic IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
593fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj{
594fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
595fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj}
596fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
597c9a43665879a03886b27a65b68af2a2c11b04f59sewardjstatic void putXMMReg ( UInt xmmreg, IRExpr* e )
598c9a43665879a03886b27a65b68af2a2c11b04f59sewardj{
599dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_V128);
600c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
601c9a43665879a03886b27a65b68af2a2c11b04f59sewardj}
602c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
60367e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardjstatic void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
60467e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj{
605dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
60667e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
60767e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj}
60867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj
609fd22645d1e2445a568dda9ae665bd3a1315dea58sewardjstatic void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
610fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj{
611dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F64);
612fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
613fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj}
614fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
6154cb918d355cef4e7640d374346852db4556f3524sewardjstatic void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
61667e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj{
617dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F32);
61867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
61967e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj}
62067e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj
6219636b44102bd3f79cba764576f34931d7b584d9esewardjstatic void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
6229636b44102bd3f79cba764576f34931d7b584d9esewardj{
623dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
6249636b44102bd3f79cba764576f34931d7b584d9esewardj   stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
6259636b44102bd3f79cba764576f34931d7b584d9esewardj}
6269636b44102bd3f79cba764576f34931d7b584d9esewardj
627e5854d6d470f21677ec84f71d09129434b044246sewardjstatic void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
628e5854d6d470f21677ec84f71d09129434b044246sewardj{
629dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
630e5854d6d470f21677ec84f71d09129434b044246sewardj   stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
631e5854d6d470f21677ec84f71d09129434b044246sewardj}
632e5854d6d470f21677ec84f71d09129434b044246sewardj
63341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardjstatic void assign ( IRTemp dst, IRExpr* e )
634d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
635dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   stmt( IRStmt_WrTmp(dst, e) );
636d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
637d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
63841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardjstatic void storeLE ( IRExpr* addr, IRExpr* data )
639d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
640e768e92e054cde495849a5c842a477d287677f78sewardj   stmt( IRStmt_Store(Iend_LE, addr, data) );
641d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
642d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
643e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardjstatic IRExpr* unop ( IROp op, IRExpr* a )
644e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj{
645e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   return IRExpr_Unop(op, a);
646e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj}
647e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
648d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardjstatic IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
649d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
650d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   return IRExpr_Binop(op, a1, a2);
651d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
652d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
653f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardjstatic IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
654f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj{
655f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj   return IRExpr_Triop(op, a1, a2, a3);
656f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj}
657f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj
658d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardjstatic IRExpr* mkexpr ( IRTemp tmp )
659d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
660dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   return IRExpr_RdTmp(tmp);
661d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
662d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
663c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardjstatic IRExpr* mkU8 ( UInt i )
664c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj{
665c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   vassert(i < 256);
6662d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj   return IRExpr_Const(IRConst_U8( (UChar)i ));
667c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj}
668c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
669c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardjstatic IRExpr* mkU16 ( UInt i )
670c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj{
671c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   vassert(i < 65536);
6722d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj   return IRExpr_Const(IRConst_U16( (UShort)i ));
673c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj}
674c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
675d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardjstatic IRExpr* mkU32 ( UInt i )
676d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
677d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   return IRExpr_Const(IRConst_U32(i));
678c9a6570e86f4252f8a486b4df48de8710d357a4asewardj}
679c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
68095535feeb27c5641608bc9eb83c047837281a7f4sewardjstatic IRExpr* mkU64 ( ULong i )
68195535feeb27c5641608bc9eb83c047837281a7f4sewardj{
68295535feeb27c5641608bc9eb83c047837281a7f4sewardj   return IRExpr_Const(IRConst_U64(i));
68395535feeb27c5641608bc9eb83c047837281a7f4sewardj}
68495535feeb27c5641608bc9eb83c047837281a7f4sewardj
68541f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardjstatic IRExpr* mkU ( IRType ty, UInt i )
68641f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj{
687c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   if (ty == Ity_I8)  return mkU8(i);
688c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   if (ty == Ity_I16) return mkU16(i);
689c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   if (ty == Ity_I32) return mkU32(i);
690e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   /* If this panics, it usually means you passed a size (1,2,4)
691e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      value as the IRType, rather than a real IRType. */
69241f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   vpanic("mkU(x86)");
69341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj}
69441f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
6951e6ad745ebafd0524da1da27a4b85524fa84f777sewardjstatic IRExpr* mkV128 ( UShort mask )
6961e6ad745ebafd0524da1da27a4b85524fa84f777sewardj{
6971e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   return IRExpr_Const(IRConst_V128(mask));
6981e6ad745ebafd0524da1da27a4b85524fa84f777sewardj}
6991e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
700e768e92e054cde495849a5c842a477d287677f78sewardjstatic IRExpr* loadLE ( IRType ty, IRExpr* addr )
70141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj{
702e768e92e054cde495849a5c842a477d287677f78sewardj   return IRExpr_Load(Iend_LE, ty, addr);
70341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj}
70441f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
70541f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardjstatic IROp mkSizedOp ( IRType ty, IROp op8 )
70641f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj{
707e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   Int adj;
70841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
70941f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
71041f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj           || op8 == Iop_Mul8
71141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj           || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
7125bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj           || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
713e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj           || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
7141fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj           || op8 == Iop_CasCmpNE8
715e13074c2c1321d069fb95806bdce64f9a3512341sewardj           || op8 == Iop_ExpCmpNE8
716eb17e49565dd7867a56c8ba6e45fdca01a576bb3sewardj           || op8 == Iop_Not8);
717e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
718e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   return adj + op8;
71941f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj}
72041f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
7219334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardjstatic IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
72241f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj{
7239334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   if (szSmall == 1 && szBig == 4) {
7249334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      return signd ? Iop_8Sto32 : Iop_8Uto32;
7259334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   }
7269334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   if (szSmall == 1 && szBig == 2) {
7279334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      return signd ? Iop_8Sto16 : Iop_8Uto16;
7289334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   }
7299334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   if (szSmall == 2 && szBig == 4) {
7309334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      return signd ? Iop_16Sto32 : Iop_16Uto32;
73141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   }
732948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   vpanic("mkWidenOp(x86,guest)");
73341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj}
73441f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
735baa660847fc52547575169bcf2be772cd16364a6sewardjstatic IRExpr* mkAnd1 ( IRExpr* x, IRExpr* y )
736baa660847fc52547575169bcf2be772cd16364a6sewardj{
737dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv,x) == Ity_I1);
738dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv,y) == Ity_I1);
739baa660847fc52547575169bcf2be772cd16364a6sewardj   return unop(Iop_32to1,
740baa660847fc52547575169bcf2be772cd16364a6sewardj               binop(Iop_And32,
741baa660847fc52547575169bcf2be772cd16364a6sewardj                     unop(Iop_1Uto32,x),
742baa660847fc52547575169bcf2be772cd16364a6sewardj                     unop(Iop_1Uto32,y)));
743baa660847fc52547575169bcf2be772cd16364a6sewardj}
744baa660847fc52547575169bcf2be772cd16364a6sewardj
745e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj/* Generate a compare-and-swap operation, operating on memory at
746e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   'addr'.  The expected value is 'expVal' and the new value is
747e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   'newVal'.  If the operation fails, then transfer control (with a
748e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   no-redir jump (XXX no -- see comment at top of this file)) to
749e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   'restart_point', which is presumably the address of the guest
750e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   instruction again -- retrying, essentially. */
751e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardjstatic void casLE ( IRExpr* addr, IRExpr* expVal, IRExpr* newVal,
752e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                    Addr32 restart_point )
753e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj{
754e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   IRCAS* cas;
755e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   IRType tyE    = typeOfIRExpr(irsb->tyenv, expVal);
756e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   IRType tyN    = typeOfIRExpr(irsb->tyenv, newVal);
757e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   IRTemp oldTmp = newTemp(tyE);
758e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   IRTemp expTmp = newTemp(tyE);
759e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   vassert(tyE == tyN);
760e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   vassert(tyE == Ity_I32 || tyE == Ity_I16 || tyE == Ity_I8);
761e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   assign(expTmp, expVal);
762e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   cas = mkIRCAS( IRTemp_INVALID, oldTmp, Iend_LE, addr,
763e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  NULL, mkexpr(expTmp), NULL, newVal );
764e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   stmt( IRStmt_CAS(cas) );
765e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   stmt( IRStmt_Exit(
7661fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj            binop( mkSizedOp(tyE,Iop_CasCmpNE8),
7671fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj                   mkexpr(oldTmp), mkexpr(expTmp) ),
768e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            Ijk_Boring, /*Ijk_NoRedir*/
769c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            IRConst_U32( restart_point ),
770c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            OFFB_EIP
771e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         ));
772e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj}
773e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
77441f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
77541f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj/*------------------------------------------------------------*/
77641f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj/*--- Helpers for %eflags.                                 ---*/
77741f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj/*------------------------------------------------------------*/
77841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
7790611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj/* -------------- Evaluating the flags-thunk. -------------- */
780c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
781e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj/* Build IR to calculate all the eflags from stored
7822a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression ::
7832a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   Ity_I32. */
7842a9ad023890d3b34cf45e429df2a8ae88b419128sewardjstatic IRExpr* mk_x86g_calculate_eflags_all ( void )
785e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj{
786f96552617c82834ece36184e674e249faa899b2fsewardj   IRExpr** args
7872a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
7882a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
7892a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
7902a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
79143c56461a667ca81fe29f1db01450d6ff1d62949sewardj   IRExpr* call
79243c56461a667ca81fe29f1db01450d6ff1d62949sewardj      = mkIRExprCCall(
79343c56461a667ca81fe29f1db01450d6ff1d62949sewardj           Ity_I32,
79443c56461a667ca81fe29f1db01450d6ff1d62949sewardj           0/*regparm*/,
7952a9ad023890d3b34cf45e429df2a8ae88b419128sewardj           "x86g_calculate_eflags_all", &x86g_calculate_eflags_all,
79643c56461a667ca81fe29f1db01450d6ff1d62949sewardj           args
79743c56461a667ca81fe29f1db01450d6ff1d62949sewardj        );
7982a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   /* Exclude OP and NDEP from definedness checking.  We're only
7992a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      interested in DEP1 and DEP2. */
8002a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
80143c56461a667ca81fe29f1db01450d6ff1d62949sewardj   return call;
802e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj}
803e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
80443c56461a667ca81fe29f1db01450d6ff1d62949sewardj/* Build IR to calculate some particular condition from stored
8052a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression ::
8062a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   Ity_Bit. */
8072a9ad023890d3b34cf45e429df2a8ae88b419128sewardjstatic IRExpr* mk_x86g_calculate_condition ( X86Condcode cond )
808e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj{
809f96552617c82834ece36184e674e249faa899b2fsewardj   IRExpr** args
8102a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      = mkIRExprVec_5( mkU32(cond),
81143c56461a667ca81fe29f1db01450d6ff1d62949sewardj                       IRExpr_Get(OFFB_CC_OP,  Ity_I32),
8122a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
8132a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
8142a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
81543c56461a667ca81fe29f1db01450d6ff1d62949sewardj   IRExpr* call
81643c56461a667ca81fe29f1db01450d6ff1d62949sewardj      = mkIRExprCCall(
81743c56461a667ca81fe29f1db01450d6ff1d62949sewardj           Ity_I32,
81843c56461a667ca81fe29f1db01450d6ff1d62949sewardj           0/*regparm*/,
8192a9ad023890d3b34cf45e429df2a8ae88b419128sewardj           "x86g_calculate_condition", &x86g_calculate_condition,
82043c56461a667ca81fe29f1db01450d6ff1d62949sewardj           args
82143c56461a667ca81fe29f1db01450d6ff1d62949sewardj        );
8222a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   /* Exclude the requested condition, OP and NDEP from definedness
8232a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      checking.  We're only interested in DEP1 and DEP2. */
8242a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
82543c56461a667ca81fe29f1db01450d6ff1d62949sewardj   return unop(Iop_32to1, call);
826e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj}
827e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
82843c56461a667ca81fe29f1db01450d6ff1d62949sewardj/* Build IR to calculate just the carry flag from stored
8292a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression :: Ity_I32. */
8302a9ad023890d3b34cf45e429df2a8ae88b419128sewardjstatic IRExpr* mk_x86g_calculate_eflags_c ( void )
83184ff0657940e62f38e618ea18bac6f27ce0e741fsewardj{
832f96552617c82834ece36184e674e249faa899b2fsewardj   IRExpr** args
8332a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
8342a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
8352a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
8362a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
83743c56461a667ca81fe29f1db01450d6ff1d62949sewardj   IRExpr* call
83843c56461a667ca81fe29f1db01450d6ff1d62949sewardj      = mkIRExprCCall(
83943c56461a667ca81fe29f1db01450d6ff1d62949sewardj           Ity_I32,
840893a3302cc943e2ad1db421a8e6a753f82f532a7sewardj           3/*regparm*/,
8412a9ad023890d3b34cf45e429df2a8ae88b419128sewardj           "x86g_calculate_eflags_c", &x86g_calculate_eflags_c,
84243c56461a667ca81fe29f1db01450d6ff1d62949sewardj           args
84343c56461a667ca81fe29f1db01450d6ff1d62949sewardj        );
8442a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   /* Exclude OP and NDEP from definedness checking.  We're only
8452a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      interested in DEP1 and DEP2. */
8462a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
84743c56461a667ca81fe29f1db01450d6ff1d62949sewardj   return call;
84884ff0657940e62f38e618ea18bac6f27ce0e741fsewardj}
84984ff0657940e62f38e618ea18bac6f27ce0e741fsewardj
850e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
8510611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj/* -------------- Building the flags-thunk. -------------- */
8520611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
853b9c5cf639b3b21b972599d27207a033afc76ef67sewardj/* The machinery in this section builds the flag-thunk following a
854b9c5cf639b3b21b972599d27207a033afc76ef67sewardj   flag-setting operation.  Hence the various setFlags_* functions.
855b9c5cf639b3b21b972599d27207a033afc76ef67sewardj*/
856b9c5cf639b3b21b972599d27207a033afc76ef67sewardj
857b9c5cf639b3b21b972599d27207a033afc76ef67sewardjstatic Bool isAddSub ( IROp op8 )
858b9c5cf639b3b21b972599d27207a033afc76ef67sewardj{
8592d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj   return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
860b9c5cf639b3b21b972599d27207a033afc76ef67sewardj}
8610611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
8622a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardjstatic Bool isLogic ( IROp op8 )
8632a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj{
8642d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj   return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
8652a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj}
8662a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj
867a238471814bd386aeb58a76718b41e68b1a794b2sewardj/* U-widen 8/16/32 bit int expr to 32. */
868c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardjstatic IRExpr* widenUto32 ( IRExpr* e )
869443cd9d34617dd7608e5dd4b4b0b4674d4f433e7sewardj{
870dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   switch (typeOfIRExpr(irsb->tyenv,e)) {
871443cd9d34617dd7608e5dd4b4b0b4674d4f433e7sewardj      case Ity_I32: return e;
872443cd9d34617dd7608e5dd4b4b0b4674d4f433e7sewardj      case Ity_I16: return unop(Iop_16Uto32,e);
873443cd9d34617dd7608e5dd4b4b0b4674d4f433e7sewardj      case Ity_I8:  return unop(Iop_8Uto32,e);
874443cd9d34617dd7608e5dd4b4b0b4674d4f433e7sewardj      default: vpanic("widenUto32");
875443cd9d34617dd7608e5dd4b4b0b4674d4f433e7sewardj   }
876443cd9d34617dd7608e5dd4b4b0b4674d4f433e7sewardj}
877443cd9d34617dd7608e5dd4b4b0b4674d4f433e7sewardj
878c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj/* S-widen 8/16/32 bit int expr to 32. */
879c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardjstatic IRExpr* widenSto32 ( IRExpr* e )
880c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj{
881dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   switch (typeOfIRExpr(irsb->tyenv,e)) {
882c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      case Ity_I32: return e;
883c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      case Ity_I16: return unop(Iop_16Sto32,e);
884c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      case Ity_I8:  return unop(Iop_8Sto32,e);
885c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      default: vpanic("widenSto32");
886c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj   }
887c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj}
888c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
889a238471814bd386aeb58a76718b41e68b1a794b2sewardj/* Narrow 8/16/32 bit int expr to 8/16/32.  Clearly only some
890a238471814bd386aeb58a76718b41e68b1a794b2sewardj   of these combinations make sense. */
891a238471814bd386aeb58a76718b41e68b1a794b2sewardjstatic IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
892a238471814bd386aeb58a76718b41e68b1a794b2sewardj{
893dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRType src_ty = typeOfIRExpr(irsb->tyenv,e);
894a238471814bd386aeb58a76718b41e68b1a794b2sewardj   if (src_ty == dst_ty)
895a238471814bd386aeb58a76718b41e68b1a794b2sewardj      return e;
896a238471814bd386aeb58a76718b41e68b1a794b2sewardj   if (src_ty == Ity_I32 && dst_ty == Ity_I16)
897a238471814bd386aeb58a76718b41e68b1a794b2sewardj      return unop(Iop_32to16, e);
898a238471814bd386aeb58a76718b41e68b1a794b2sewardj   if (src_ty == Ity_I32 && dst_ty == Ity_I8)
899a238471814bd386aeb58a76718b41e68b1a794b2sewardj      return unop(Iop_32to8, e);
900a238471814bd386aeb58a76718b41e68b1a794b2sewardj
901a238471814bd386aeb58a76718b41e68b1a794b2sewardj   vex_printf("\nsrc, dst tys are: ");
902a238471814bd386aeb58a76718b41e68b1a794b2sewardj   ppIRType(src_ty);
903a238471814bd386aeb58a76718b41e68b1a794b2sewardj   vex_printf(", ");
904a238471814bd386aeb58a76718b41e68b1a794b2sewardj   ppIRType(dst_ty);
905a238471814bd386aeb58a76718b41e68b1a794b2sewardj   vex_printf("\n");
906a238471814bd386aeb58a76718b41e68b1a794b2sewardj   vpanic("narrowTo(x86)");
907a238471814bd386aeb58a76718b41e68b1a794b2sewardj}
908a238471814bd386aeb58a76718b41e68b1a794b2sewardj
909443cd9d34617dd7608e5dd4b4b0b4674d4f433e7sewardj
9102a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj/* Set the flags thunk OP, DEP1 and DEP2 fields.  The supplied op is
911948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   auto-sized up to the real op. */
9120611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
9132a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardjstatic
9142a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardjvoid setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
9150611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj{
916b9c5cf639b3b21b972599d27207a033afc76ef67sewardj   Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
9170611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
9180611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
9190611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
9200611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   switch (op8) {
9212a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case Iop_Add8: ccOp += X86G_CC_OP_ADDB;   break;
9222a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case Iop_Sub8: ccOp += X86G_CC_OP_SUBB;   break;
9230611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      default:       ppIROp(op8);
9242a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                     vpanic("setFlags_DEP1_DEP2(x86)");
925b9c5cf639b3b21b972599d27207a033afc76ef67sewardj   }
9262a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(ccOp)) );
9272a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
9282a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
929a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
930a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      elimination of previous stores to this field work better. */
931a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
932b9c5cf639b3b21b972599d27207a033afc76ef67sewardj}
933b9c5cf639b3b21b972599d27207a033afc76ef67sewardj
934b9c5cf639b3b21b972599d27207a033afc76ef67sewardj
9352a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj/* Set the OP and DEP1 fields only, and write zero to DEP2. */
936b9c5cf639b3b21b972599d27207a033afc76ef67sewardj
9372a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardjstatic
9382a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardjvoid setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
939b9c5cf639b3b21b972599d27207a033afc76ef67sewardj{
940b9c5cf639b3b21b972599d27207a033afc76ef67sewardj   Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
941b9c5cf639b3b21b972599d27207a033afc76ef67sewardj
942b9c5cf639b3b21b972599d27207a033afc76ef67sewardj   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
943b9c5cf639b3b21b972599d27207a033afc76ef67sewardj
944b9c5cf639b3b21b972599d27207a033afc76ef67sewardj   switch (op8) {
945b9c5cf639b3b21b972599d27207a033afc76ef67sewardj      case Iop_Or8:
946b9c5cf639b3b21b972599d27207a033afc76ef67sewardj      case Iop_And8:
9472a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case Iop_Xor8: ccOp += X86G_CC_OP_LOGICB; break;
948b9c5cf639b3b21b972599d27207a033afc76ef67sewardj      default:       ppIROp(op8);
9492a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                     vpanic("setFlags_DEP1(x86)");
9500611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   }
9512a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(ccOp)) );
9522a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
9532a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
954a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
955a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      elimination of previous stores to this field work better. */
956a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
9570611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj}
9580611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
9590611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
960948d48be23eca9df7b9d33be5dca499affb7cb3asewardj/* For shift operations, we put in the result and the undershifted
961948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   result.  Except if the shift amount is zero, the thunk is left
962948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   unchanged. */
9630611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
9642a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardjstatic void setFlags_DEP1_DEP2_shift ( IROp    op32,
9652a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                                       IRTemp  res,
9662a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                                       IRTemp  resUS,
9672a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                                       IRType  ty,
9682a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                                       IRTemp  guard )
9690611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj{
970c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj   Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
9710611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
9720611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
9730611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   vassert(guard);
9740611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
9752a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   /* Both kinds of right shifts are handled by the same thunk
9762a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      operation. */
977c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj   switch (op32) {
978c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      case Iop_Shr32:
9792a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case Iop_Sar32: ccOp = X86G_CC_OP_SHRL - ccOp; break;
9802a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case Iop_Shl32: ccOp = X86G_CC_OP_SHLL - ccOp; break;
981c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      default:        ppIROp(op32);
9822a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                      vpanic("setFlags_DEP1_DEP2_shift(x86)");
9830611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   }
9840611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
985009230b9758291b594e60d7c0243a73d53e81854sewardj   /* guard :: Ity_I8.  We need to convert it to I1. */
986009230b9758291b594e60d7c0243a73d53e81854sewardj   IRTemp guardB = newTemp(Ity_I1);
987009230b9758291b594e60d7c0243a73d53e81854sewardj   assign( guardB, binop(Iop_CmpNE8, mkexpr(guard), mkU8(0)) );
988009230b9758291b594e60d7c0243a73d53e81854sewardj
9892a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   /* DEP1 contains the result, DEP2 contains the undershifted value. */
990eeb9ef8549a9c4aa15cbfbda52e20703d778fc61sewardj   stmt( IRStmt_Put( OFFB_CC_OP,
99199dd03e04a6914d90d5fee727d61d76905334becflorian                     IRExpr_ITE( mkexpr(guardB),
99299dd03e04a6914d90d5fee727d61d76905334becflorian                                 mkU32(ccOp),
99399dd03e04a6914d90d5fee727d61d76905334becflorian                                 IRExpr_Get(OFFB_CC_OP,Ity_I32) ) ));
9942a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP1,
99599dd03e04a6914d90d5fee727d61d76905334becflorian                     IRExpr_ITE( mkexpr(guardB),
99699dd03e04a6914d90d5fee727d61d76905334becflorian                                 widenUto32(mkexpr(res)),
99799dd03e04a6914d90d5fee727d61d76905334becflorian                                 IRExpr_Get(OFFB_CC_DEP1,Ity_I32) ) ));
9982a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP2,
99999dd03e04a6914d90d5fee727d61d76905334becflorian                     IRExpr_ITE( mkexpr(guardB),
100099dd03e04a6914d90d5fee727d61d76905334becflorian                                 widenUto32(mkexpr(resUS)),
100199dd03e04a6914d90d5fee727d61d76905334becflorian                                 IRExpr_Get(OFFB_CC_DEP2,Ity_I32) ) ));
1002a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
1003a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      elimination of previous stores to this field work better. */
100417b0e21a9696ec86fa039c252a516fb8c3bb1a60sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP,
100599dd03e04a6914d90d5fee727d61d76905334becflorian                     IRExpr_ITE( mkexpr(guardB),
100699dd03e04a6914d90d5fee727d61d76905334becflorian                                 mkU32(0),
100799dd03e04a6914d90d5fee727d61d76905334becflorian                                 IRExpr_Get(OFFB_CC_NDEP,Ity_I32) ) ));
10080611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj}
10090611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
10100611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
10112a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj/* For the inc/dec case, we store in DEP1 the result value and in NDEP
1012948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   the former value of the carry flag, which unfortunately we have to
1013948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   compute. */
10140611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
1015948d48be23eca9df7b9d33be5dca499affb7cb3asewardjstatic void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
10160611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj{
10172a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   Int ccOp = inc ? X86G_CC_OP_INCB : X86G_CC_OP_DECB;
10180611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
10190611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
10200611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
10210611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
10220611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   /* This has to come first, because calculating the C flag
10232a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      may require reading all four thunk fields. */
10242a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mk_x86g_calculate_eflags_c()) );
10252a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(ccOp)) );
1026478646f54befaba01cbceb40fd5e46cdf562fdb5sewardj   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(res))) );
10272a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
10280611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj}
10290611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
10300611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
10312a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
10322a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   two arguments. */
1033cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
1034cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardjstatic
10352a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardjvoid setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
1036cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj{
1037cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   switch (ty) {
10382a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      case Ity_I8:
10392a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
10402a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         break;
10412a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      case Ity_I16:
10422a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
10432a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         break;
10442a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      case Ity_I32:
10452a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
10462a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         break;
10472a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      default:
10482a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         vpanic("setFlags_MUL(x86)");
1049cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   }
10502a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
10512a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
1052a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
1053a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      elimination of previous stores to this field work better. */
1054a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
1055cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj}
1056cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
1057cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
10583af115ff8c215db41dff92da266a036c59eaec95sewardj/* -------------- Condition codes. -------------- */
10593af115ff8c215db41dff92da266a036c59eaec95sewardj
1060e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj/* Condition codes, using the Intel encoding.  */
10610611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
106255085f8680acc89d727e321f3b34cae1a8c4093aflorianstatic const HChar* name_X86Condcode ( X86Condcode cond )
1063e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj{
1064e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   switch (cond) {
10652a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondO:      return "o";
10662a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondNO:     return "no";
10672a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondB:      return "b";
10682a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondNB:     return "nb";
10692a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondZ:      return "z";
10702a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondNZ:     return "nz";
10712a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondBE:     return "be";
10722a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondNBE:    return "nbe";
10732a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondS:      return "s";
10742a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondNS:     return "ns";
10752a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondP:      return "p";
10762a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondNP:     return "np";
10772a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondL:      return "l";
10782a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondNL:     return "nl";
10792a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondLE:     return "le";
10802a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondNLE:    return "nle";
10812a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      case X86CondAlways: return "ALWAYS";
10822a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      default: vpanic("name_X86Condcode");
1083e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   }
1084e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj}
1085e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
10862a9ad023890d3b34cf45e429df2a8ae88b419128sewardjstatic
10872a9ad023890d3b34cf45e429df2a8ae88b419128sewardjX86Condcode positiveIse_X86Condcode ( X86Condcode  cond,
1088dbf550c3bb7d82eca7ea1436466dd51761fb7d4bsewardj                                      Bool*        needInvert )
1089e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj{
10902a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   vassert(cond >= X86CondO && cond <= X86CondNLE);
1091e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   if (cond & 1) {
1092e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      *needInvert = True;
1093e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      return cond-1;
1094e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   } else {
1095e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      *needInvert = False;
1096e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      return cond;
1097e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   }
1098e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj}
1099e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1100e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
11013af115ff8c215db41dff92da266a036c59eaec95sewardj/* -------------- Helpers for ADD/SUB with carry. -------------- */
11023af115ff8c215db41dff92da266a036c59eaec95sewardj
1103948d48be23eca9df7b9d33be5dca499affb7cb3asewardj/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
11042a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   appropriately.
1105e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
1106e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   Optionally, generate a store for the 'tres' value.  This can either
1107e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   be a normal store, or it can be a cas-with-possible-failure style
1108e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   store:
1109e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
1110e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   if taddr is IRTemp_INVALID, then no store is generated.
1111e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
1112e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   if taddr is not IRTemp_INVALID, then a store (using taddr as
1113e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   the address) is generated:
1114e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
1115e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj     if texpVal is IRTemp_INVALID then a normal store is
1116e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj     generated, and restart_point must be zero (it is irrelevant).
1117e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
1118e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj     if texpVal is not IRTemp_INVALID then a cas-style store is
1119e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj     generated.  texpVal is the expected value, restart_point
1120e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj     is the restart point if the store fails, and texpVal must
1121e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj     have the same type as tres.
11223af115ff8c215db41dff92da266a036c59eaec95sewardj*/
11233af115ff8c215db41dff92da266a036c59eaec95sewardjstatic void helper_ADC ( Int sz,
1124e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                         IRTemp tres, IRTemp ta1, IRTemp ta2,
1125e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                         /* info about optional store: */
1126e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                         IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
11273af115ff8c215db41dff92da266a036c59eaec95sewardj{
11283af115ff8c215db41dff92da266a036c59eaec95sewardj   UInt    thunkOp;
11292a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   IRType  ty    = szToITy(sz);
11302a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   IRTemp  oldc  = newTemp(Ity_I32);
11312a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   IRTemp  oldcn = newTemp(ty);
11322a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   IROp    plus  = mkSizedOp(ty, Iop_Add8);
11332a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   IROp    xor   = mkSizedOp(ty, Iop_Xor8);
11342a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj
1135e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
11362a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   vassert(sz == 1 || sz == 2 || sz == 4);
11372a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   thunkOp = sz==4 ? X86G_CC_OP_ADCL
11382a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                   : (sz==2 ? X86G_CC_OP_ADCW : X86G_CC_OP_ADCB);
11393af115ff8c215db41dff92da266a036c59eaec95sewardj
11403af115ff8c215db41dff92da266a036c59eaec95sewardj   /* oldc = old carry flag, 0 or 1 */
11412a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   assign( oldc,  binop(Iop_And32,
11422a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                        mk_x86g_calculate_eflags_c(),
11435bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                        mkU32(1)) );
11443af115ff8c215db41dff92da266a036c59eaec95sewardj
11452a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1146a238471814bd386aeb58a76718b41e68b1a794b2sewardj
11472a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   assign( tres, binop(plus,
11482a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                       binop(plus,mkexpr(ta1),mkexpr(ta2)),
11492a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                       mkexpr(oldcn)) );
11502a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj
1151e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* Possibly generate a store of 'tres' to 'taddr'.  See comment at
1152e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      start of this function. */
1153e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   if (taddr != IRTemp_INVALID) {
1154e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      if (texpVal == IRTemp_INVALID) {
1155e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         vassert(restart_point == 0);
1156e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         storeLE( mkexpr(taddr), mkexpr(tres) );
1157e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      } else {
1158e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1159e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* .. and hence 'texpVal' has the same type as 'tres'. */
1160e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         casLE( mkexpr(taddr),
1161e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                mkexpr(texpVal), mkexpr(tres), restart_point );
1162e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      }
1163e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
1164e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
11652a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(thunkOp) ) );
11663b3eacdfb862ea8571bec0018d2bc6ad7de5e328sewardj   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1)) ));
11673b3eacdfb862ea8571bec0018d2bc6ad7de5e328sewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
11683b3eacdfb862ea8571bec0018d2bc6ad7de5e328sewardj                                                         mkexpr(oldcn)) )) );
11692a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
11703af115ff8c215db41dff92da266a036c59eaec95sewardj}
11713af115ff8c215db41dff92da266a036c59eaec95sewardj
11723af115ff8c215db41dff92da266a036c59eaec95sewardj
1173948d48be23eca9df7b9d33be5dca499affb7cb3asewardj/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
1174e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   appropriately.  As with helper_ADC, possibly generate a store of
1175e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   the result -- see comments on helper_ADC for details.
1176caca9d0d3729c36af6ae02b0654cb289101248cbsewardj*/
1177caca9d0d3729c36af6ae02b0654cb289101248cbsewardjstatic void helper_SBB ( Int sz,
1178e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                         IRTemp tres, IRTemp ta1, IRTemp ta2,
1179e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                         /* info about optional store: */
1180e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                         IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
1181caca9d0d3729c36af6ae02b0654cb289101248cbsewardj{
1182caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   UInt    thunkOp;
11832a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   IRType  ty    = szToITy(sz);
11842a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   IRTemp  oldc  = newTemp(Ity_I32);
11852a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   IRTemp  oldcn = newTemp(ty);
11862a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   IROp    minus = mkSizedOp(ty, Iop_Sub8);
11872a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   IROp    xor   = mkSizedOp(ty, Iop_Xor8);
11882a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj
1189e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
11902a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   vassert(sz == 1 || sz == 2 || sz == 4);
11912a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   thunkOp = sz==4 ? X86G_CC_OP_SBBL
11922a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                   : (sz==2 ? X86G_CC_OP_SBBW : X86G_CC_OP_SBBB);
1193caca9d0d3729c36af6ae02b0654cb289101248cbsewardj
1194caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   /* oldc = old carry flag, 0 or 1 */
1195a238471814bd386aeb58a76718b41e68b1a794b2sewardj   assign( oldc, binop(Iop_And32,
11962a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                       mk_x86g_calculate_eflags_c(),
11975bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                       mkU32(1)) );
1198caca9d0d3729c36af6ae02b0654cb289101248cbsewardj
11992a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1200a238471814bd386aeb58a76718b41e68b1a794b2sewardj
12012a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   assign( tres, binop(minus,
12022a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                       binop(minus,mkexpr(ta1),mkexpr(ta2)),
12032a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                       mkexpr(oldcn)) );
12042a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj
1205e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* Possibly generate a store of 'tres' to 'taddr'.  See comment at
1206e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      start of this function. */
1207e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   if (taddr != IRTemp_INVALID) {
1208e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      if (texpVal == IRTemp_INVALID) {
1209e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         vassert(restart_point == 0);
1210e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         storeLE( mkexpr(taddr), mkexpr(tres) );
1211e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      } else {
1212e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1213e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* .. and hence 'texpVal' has the same type as 'tres'. */
1214e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         casLE( mkexpr(taddr),
1215e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                mkexpr(texpVal), mkexpr(tres), restart_point );
1216e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      }
1217e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
1218e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
12192a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(thunkOp) ) );
12203b3eacdfb862ea8571bec0018d2bc6ad7de5e328sewardj   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1) )) );
12213b3eacdfb862ea8571bec0018d2bc6ad7de5e328sewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
12223b3eacdfb862ea8571bec0018d2bc6ad7de5e328sewardj                                                         mkexpr(oldcn)) )) );
12232a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1224caca9d0d3729c36af6ae02b0654cb289101248cbsewardj}
1225caca9d0d3729c36af6ae02b0654cb289101248cbsewardj
1226caca9d0d3729c36af6ae02b0654cb289101248cbsewardj
12277dd2eb24e733858af3260372ac6cb74a671a94b6sewardj/* -------------- Helpers for disassembly printing. -------------- */
122841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
122955085f8680acc89d727e321f3b34cae1a8c4093aflorianstatic const HChar* nameGrp1 ( Int opc_aux )
123041f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj{
123155085f8680acc89d727e321f3b34cae1a8c4093aflorian   static const HChar* grp1_names[8]
123241f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj     = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
123341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
123441f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   return grp1_names[opc_aux];
123541f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj}
123641f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
123755085f8680acc89d727e321f3b34cae1a8c4093aflorianstatic const HChar* nameGrp2 ( Int opc_aux )
1238e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj{
123955085f8680acc89d727e321f3b34cae1a8c4093aflorian   static const HChar* grp2_names[8]
1240e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj     = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
1241c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
1242e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   return grp2_names[opc_aux];
1243e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj}
1244e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
124555085f8680acc89d727e321f3b34cae1a8c4093aflorianstatic const HChar* nameGrp4 ( Int opc_aux )
1246c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj{
124755085f8680acc89d727e321f3b34cae1a8c4093aflorian   static const HChar* grp4_names[8]
1248c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj     = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1249c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1250c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   return grp4_names[opc_aux];
1251c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj}
12520611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
125355085f8680acc89d727e321f3b34cae1a8c4093aflorianstatic const HChar* nameGrp5 ( Int opc_aux )
12540611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj{
125555085f8680acc89d727e321f3b34cae1a8c4093aflorian   static const HChar* grp5_names[8]
12560611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj     = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
12570611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
12580611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   return grp5_names[opc_aux];
12590611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj}
12600611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
126155085f8680acc89d727e321f3b34cae1a8c4093aflorianstatic const HChar* nameGrp8 ( Int opc_aux )
1262490ad3820487e34854c46befcc9c755d6afc2519sewardj{
126355085f8680acc89d727e321f3b34cae1a8c4093aflorian   static const HChar* grp8_names[8]
1264490ad3820487e34854c46befcc9c755d6afc2519sewardj     = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1265490ad3820487e34854c46befcc9c755d6afc2519sewardj   if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(x86)");
1266490ad3820487e34854c46befcc9c755d6afc2519sewardj   return grp8_names[opc_aux];
1267490ad3820487e34854c46befcc9c755d6afc2519sewardj}
1268c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
126955085f8680acc89d727e321f3b34cae1a8c4093aflorianstatic const HChar* nameIReg ( Int size, Int reg )
1270c9a6570e86f4252f8a486b4df48de8710d357a4asewardj{
127155085f8680acc89d727e321f3b34cae1a8c4093aflorian   static const HChar* ireg32_names[8]
1272c9a6570e86f4252f8a486b4df48de8710d357a4asewardj     = { "%eax", "%ecx", "%edx", "%ebx",
1273c9a6570e86f4252f8a486b4df48de8710d357a4asewardj         "%esp", "%ebp", "%esi", "%edi" };
127455085f8680acc89d727e321f3b34cae1a8c4093aflorian   static const HChar* ireg16_names[8]
1275c9a6570e86f4252f8a486b4df48de8710d357a4asewardj     = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
127655085f8680acc89d727e321f3b34cae1a8c4093aflorian   static const HChar* ireg8_names[8]
1277c9a6570e86f4252f8a486b4df48de8710d357a4asewardj     = { "%al", "%cl", "%dl", "%bl",
1278c9a6570e86f4252f8a486b4df48de8710d357a4asewardj         "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1279c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   if (reg < 0 || reg > 7) goto bad;
1280c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   switch (size) {
1281c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      case 4: return ireg32_names[reg];
1282c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      case 2: return ireg16_names[reg];
1283c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      case 1: return ireg8_names[reg];
1284c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   }
1285c9a6570e86f4252f8a486b4df48de8710d357a4asewardj  bad:
1286c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   vpanic("nameIReg(X86)");
1287c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   return NULL; /*notreached*/
1288c9a6570e86f4252f8a486b4df48de8710d357a4asewardj}
1289c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
129055085f8680acc89d727e321f3b34cae1a8c4093aflorianstatic const HChar* nameSReg ( UInt sreg )
1291063f02f7e77ca024d24786bec402ca296a05bd6esewardj{
1292063f02f7e77ca024d24786bec402ca296a05bd6esewardj   switch (sreg) {
1293063f02f7e77ca024d24786bec402ca296a05bd6esewardj      case R_ES: return "%es";
1294063f02f7e77ca024d24786bec402ca296a05bd6esewardj      case R_CS: return "%cs";
1295063f02f7e77ca024d24786bec402ca296a05bd6esewardj      case R_SS: return "%ss";
1296063f02f7e77ca024d24786bec402ca296a05bd6esewardj      case R_DS: return "%ds";
1297063f02f7e77ca024d24786bec402ca296a05bd6esewardj      case R_FS: return "%fs";
1298063f02f7e77ca024d24786bec402ca296a05bd6esewardj      case R_GS: return "%gs";
1299063f02f7e77ca024d24786bec402ca296a05bd6esewardj      default: vpanic("nameSReg(x86)");
1300063f02f7e77ca024d24786bec402ca296a05bd6esewardj   }
1301063f02f7e77ca024d24786bec402ca296a05bd6esewardj}
1302063f02f7e77ca024d24786bec402ca296a05bd6esewardj
130355085f8680acc89d727e321f3b34cae1a8c4093aflorianstatic const HChar* nameMMXReg ( Int mmxreg )
1304464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
130555085f8680acc89d727e321f3b34cae1a8c4093aflorian   static const HChar* mmx_names[8]
1306464efa446b2db97115d3e5f04af5db3464cc0e93sewardj     = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1307464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1308464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   return mmx_names[mmxreg];
1309464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
1310464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
131155085f8680acc89d727e321f3b34cae1a8c4093aflorianstatic const HChar* nameXMMReg ( Int xmmreg )
1312c9a43665879a03886b27a65b68af2a2c11b04f59sewardj{
131355085f8680acc89d727e321f3b34cae1a8c4093aflorian   static const HChar* xmm_names[8]
1314c9a43665879a03886b27a65b68af2a2c11b04f59sewardj     = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1315c9a43665879a03886b27a65b68af2a2c11b04f59sewardj         "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1316c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   if (xmmreg < 0 || xmmreg > 7) vpanic("name_of_xmm_reg");
1317c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   return xmm_names[xmmreg];
1318c9a43665879a03886b27a65b68af2a2c11b04f59sewardj}
1319464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
132055085f8680acc89d727e321f3b34cae1a8c4093aflorianstatic const HChar* nameMMXGran ( Int gran )
1321464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
1322464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   switch (gran) {
1323464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0: return "b";
1324464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 1: return "w";
1325464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 2: return "d";
1326464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 3: return "q";
1327464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      default: vpanic("nameMMXGran(x86,guest)");
1328464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   }
1329464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
1330c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
13312d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardjstatic HChar nameISize ( Int size )
1332c9a6570e86f4252f8a486b4df48de8710d357a4asewardj{
1333c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   switch (size) {
1334c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      case 4: return 'l';
1335c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      case 2: return 'w';
1336c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      case 1: return 'b';
1337c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      default: vpanic("nameISize(x86)");
1338c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   }
1339c9a6570e86f4252f8a486b4df48de8710d357a4asewardj}
1340c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
1341d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1342d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/*------------------------------------------------------------*/
1343d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/*--- JMP helpers                                          ---*/
1344d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/*------------------------------------------------------------*/
1345d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1346c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardjstatic void jmp_lit( /*MOD*/DisResult* dres,
1347c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     IRJumpKind kind, Addr32 d32 )
1348d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
1349c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->whatNext    == Dis_Continue);
1350c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->len         == 0);
1351c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->continueAt  == 0);
1352c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->jk_StopHere == Ijk_INVALID);
1353c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres->whatNext    = Dis_StopHere;
1354c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres->jk_StopHere = kind;
1355c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   stmt( IRStmt_Put( OFFB_EIP, mkU32(d32) ) );
1356d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
1357d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1358c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardjstatic void jmp_treg( /*MOD*/DisResult* dres,
1359c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                      IRJumpKind kind, IRTemp t )
1360e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj{
1361c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->whatNext    == Dis_Continue);
1362c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->len         == 0);
1363c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->continueAt  == 0);
1364c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->jk_StopHere == Ijk_INVALID);
1365c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres->whatNext    = Dis_StopHere;
1366c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres->jk_StopHere = kind;
1367c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   stmt( IRStmt_Put( OFFB_EIP, mkexpr(t) ) );
1368e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj}
1369e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
13702a9ad023890d3b34cf45e429df2a8ae88b419128sewardjstatic
1371c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardjvoid jcc_01( /*MOD*/DisResult* dres,
1372c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj             X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
1373e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj{
13742a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   Bool        invert;
13752a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   X86Condcode condPos;
1376c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->whatNext    == Dis_Continue);
1377c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->len         == 0);
1378c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->continueAt  == 0);
1379c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->jk_StopHere == Ijk_INVALID);
1380c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres->whatNext    = Dis_StopHere;
1381c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres->jk_StopHere = Ijk_Boring;
13822a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   condPos = positiveIse_X86Condcode ( cond, &invert );
1383e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   if (invert) {
13842a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
1385893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                         Ijk_Boring,
1386c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                         IRConst_U32(d32_false),
1387c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                         OFFB_EIP ) );
1388c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      stmt( IRStmt_Put( OFFB_EIP, mkU32(d32_true) ) );
1389e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   } else {
13902a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
1391893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                         Ijk_Boring,
1392c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                         IRConst_U32(d32_true),
1393c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                         OFFB_EIP ) );
1394c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      stmt( IRStmt_Put( OFFB_EIP, mkU32(d32_false) ) );
1395e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   }
1396e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj}
1397c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
1398c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
1399d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/*------------------------------------------------------------*/
1400d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/*--- Disassembling addressing modes                       ---*/
1401d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/*------------------------------------------------------------*/
1402d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1403d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardjstatic
140455085f8680acc89d727e321f3b34cae1a8c4093aflorianconst HChar* sorbTxt ( UChar sorb )
1405d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
1406d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   switch (sorb) {
1407d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0:    return ""; /* no override */
1408d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x3E: return "%ds";
1409d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x26: return "%es:";
1410d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x64: return "%fs:";
1411d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x65: return "%gs:";
1412ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      case 0x36: return "%ss:";
14137df596b1e36840e2d74c90aa55589934add61ccfsewardj      default: vpanic("sorbTxt(x86,guest)");
1414d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   }
1415d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
1416d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1417d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14187df596b1e36840e2d74c90aa55589934add61ccfsewardj/* 'virtual' is an IRExpr* holding a virtual address.  Convert it to a
14197df596b1e36840e2d74c90aa55589934add61ccfsewardj   linear address by adding any required segment override as indicated
14207df596b1e36840e2d74c90aa55589934add61ccfsewardj   by sorb. */
1421d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardjstatic
1422d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardjIRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1423d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
14243bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   Int    sreg;
14253bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   IRType hWordTy;
14263bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
1427d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1428d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   if (sorb == 0)
1429d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* the common case - no override */
1430d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      return virtual;
1431d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1432d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   switch (sorb) {
1433d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x3E: sreg = R_DS; break;
1434d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x26: sreg = R_ES; break;
1435d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x64: sreg = R_FS; break;
1436d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x65: sreg = R_GS; break;
1437ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      case 0x36: sreg = R_SS; break;
14387df596b1e36840e2d74c90aa55589934add61ccfsewardj      default: vpanic("handleSegOverride(x86,guest)");
1439d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   }
1440d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14413bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
14427df596b1e36840e2d74c90aa55589934add61ccfsewardj
14433bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   seg_selector = newTemp(Ity_I32);
14443bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   ldt_ptr      = newTemp(hWordTy);
14453bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   gdt_ptr      = newTemp(hWordTy);
14463bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   r64          = newTemp(Ity_I64);
14477df596b1e36840e2d74c90aa55589934add61ccfsewardj
14483bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
14493bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
14503bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
1451d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14523bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   /*
14533bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   Call this to do the translation and limit checks:
14543bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
14553bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                                 UInt seg_selector, UInt virtual_addr )
14563bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   */
14573bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   assign(
14583bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj      r64,
14593bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj      mkIRExprCCall(
14603bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj         Ity_I64,
14613bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj         0/*regparms*/,
14623bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj         "x86g_use_seg_selector",
14633bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj         &x86g_use_seg_selector,
14643bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj         mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
14653bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                        mkexpr(seg_selector), virtual)
14663bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj      )
14673bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   );
1468d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
146952444cb6696efd612ced78daa8feb235808ef165sewardj   /* If the high 32 of the result are non-zero, there was a
147052444cb6696efd612ced78daa8feb235808ef165sewardj      failure in address translation.  In which case, make a
147152444cb6696efd612ced78daa8feb235808ef165sewardj      quick exit.
147252444cb6696efd612ced78daa8feb235808ef165sewardj   */
147352444cb6696efd612ced78daa8feb235808ef165sewardj   stmt(
147452444cb6696efd612ced78daa8feb235808ef165sewardj      IRStmt_Exit(
147552444cb6696efd612ced78daa8feb235808ef165sewardj         binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
147652444cb6696efd612ced78daa8feb235808ef165sewardj         Ijk_MapFail,
1477c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         IRConst_U32( guest_EIP_curr_instr ),
1478c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         OFFB_EIP
147952444cb6696efd612ced78daa8feb235808ef165sewardj      )
148052444cb6696efd612ced78daa8feb235808ef165sewardj   );
148152444cb6696efd612ced78daa8feb235808ef165sewardj
148252444cb6696efd612ced78daa8feb235808ef165sewardj   /* otherwise, here's the translated result. */
14833bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   return unop(Iop_64to32, mkexpr(r64));
1484d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
1485d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1486d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1487d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/* Generate IR to calculate an address indicated by a ModRM and
1488d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   following SIB bytes.  The expression, and the number of bytes in
1489d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   the address mode, are returned.  Note that this fn should not be
1490d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   called if the R/M part of the address denotes a register instead of
1491d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   memory.  If print_codegen is true, text of the addressing mode is
1492940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   placed in buf.
1493940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
1494940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   The computed address is stored in a new tempreg, and the
1495940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   identity of the tempreg is returned.  */
1496940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
1497940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardjstatic IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1498940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj{
1499940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   IRTemp tmp = newTemp(Ity_I32);
1500940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   assign( tmp, addr32 );
1501940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   return tmp;
1502940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj}
1503d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1504d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardjstatic
150552d049186d07991237a825ec88aa7f1f303edb70sewardjIRTemp disAMode ( Int* len, UChar sorb, Int delta, HChar* buf )
1506d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
1507d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   UChar mod_reg_rm = getIByte(delta);
1508d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   delta++;
1509d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
15109ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj   buf[0] = (UChar)0;
15119ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj
1512d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1513d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      jump table seems a bit excessive.
1514d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   */
15159b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj   mod_reg_rm &= 0xC7;                      /* is now XX000YYY */
15169b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj   mod_reg_rm  = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
15179b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj                                            /* is now XX0XXYYY */
15189b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj   mod_reg_rm &= 0x1F;                      /* is now 000XXYYY */
1519d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   switch (mod_reg_rm) {
1520d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1521d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1522d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         --> GET %reg, t
1523d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      */
1524d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x00: case 0x01: case 0x02: case 0x03:
1525d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1526d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         { UChar rm = mod_reg_rm;
1527d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj           DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1528d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj           *len = 1;
15295bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj           return disAMode_copy2tmp(
1530940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                  handleSegOverride(sorb, getIReg(4,rm)));
1531d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1532d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1533d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* d8(%eax) ... d8(%edi), not including d8(%esp)
1534d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         --> GET %reg, t ; ADDL d8, t
1535d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      */
1536d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x08: case 0x09: case 0x0A: case 0x0B:
1537d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
15389b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         { UChar rm = toUChar(mod_reg_rm & 7);
1539d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj           UInt  d  = getSDisp8(delta);
15402d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj           DIS(buf, "%s%d(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
15415bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj           *len = 2;
15425bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj           return disAMode_copy2tmp(
1543940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                  handleSegOverride(sorb,
1544940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                     binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
1545d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1546d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1547d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* d32(%eax) ... d32(%edi), not including d32(%esp)
1548d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         --> GET %reg, t ; ADDL d8, t
1549d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      */
1550d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x10: case 0x11: case 0x12: case 0x13:
1551d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* ! 14 */ case 0x15: case 0x16: case 0x17:
15529b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         { UChar rm = toUChar(mod_reg_rm & 7);
1553d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj           UInt  d  = getUDisp32(delta);
1554b173774421d015736c2316b5e6e998e7de545a5cflorian           DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
15555bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj           *len = 5;
15565bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj           return disAMode_copy2tmp(
1557940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                  handleSegOverride(sorb,
1558940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                     binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
1559d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1560d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1561d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* a register, %eax .. %edi.  This shouldn't happen. */
1562d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x18: case 0x19: case 0x1A: case 0x1B:
1563d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1564d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         vpanic("disAMode(x86): not an addr!");
1565d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1566d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* a 32-bit literal address
1567d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         --> MOV d32, tmp
1568d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      */
1569d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x05:
1570d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         { UInt d = getUDisp32(delta);
1571d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj           *len = 5;
1572d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj           DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
1573940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj           return disAMode_copy2tmp(
1574940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                     handleSegOverride(sorb, mkU32(d)));
1575d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1576d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1577d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x04: {
1578d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         /* SIB, with no displacement.  Special cases:
1579d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            -- %esp cannot act as an index value.
1580d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               If index_r indicates %esp, zero is used for the index.
1581d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            -- when mod is zero and base indicates EBP, base is instead
1582d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               a 32-bit literal.
1583d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            It's all madness, I tell you.  Extract %index, %base and
1584d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            scale from the SIB byte.  The value denoted is then:
1585d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               | %index == %ESP && %base == %EBP
1586d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               = d32 following SIB byte
1587d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               | %index == %ESP && %base != %EBP
1588d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               = %base
1589d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               | %index != %ESP && %base == %EBP
1590d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               = d32 following SIB byte + (%index << scale)
1591d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               | %index != %ESP && %base != %ESP
1592d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               = %base + (%index << scale)
1593d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1594d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            What happens to the souls of CPU architects who dream up such
1595d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            horrendous schemes, do you suppose?
1596d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         */
1597d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         UChar sib     = getIByte(delta);
15989b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar scale   = toUChar((sib >> 6) & 3);
15999b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar index_r = toUChar((sib >> 3) & 7);
16009b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar base_r  = toUChar(sib & 7);
16015bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         delta++;
1602d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1603d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (index_r != R_ESP && base_r != R_EBP) {
1604d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1605d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                      nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
16065bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 2;
1607940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            return
1608940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj               disAMode_copy2tmp(
16095bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               handleSegOverride(sorb,
16105bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                  binop(Iop_Add32,
1611d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                        getIReg(4,base_r),
1612d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                        binop(Iop_Shl32, getIReg(4,index_r),
16136d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj                              mkU8(scale)))));
1614d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1615d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1616d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (index_r != R_ESP && base_r == R_EBP) {
1617d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            UInt d = getUDisp32(delta);
1618d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1619d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                      nameIReg(4,index_r), 1<<scale);
1620d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            *len = 6;
1621d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            return
1622940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj               disAMode_copy2tmp(
1623d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               handleSegOverride(sorb,
16245bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                  binop(Iop_Add32,
16255bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                        binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
1626940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                        mkU32(d))));
1627d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1628d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1629d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (index_r == R_ESP && base_r != R_EBP) {
1630d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
16315bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 2;
16325bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            return disAMode_copy2tmp(
1633940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                   handleSegOverride(sorb, getIReg(4,base_r)));
1634d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1635d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1636d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (index_r == R_ESP && base_r == R_EBP) {
1637d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            UInt d = getUDisp32(delta);
16389c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj            DIS(buf, "%s0x%x(,,)", sorbTxt(sorb), d);
16395bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 6;
16405bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            return disAMode_copy2tmp(
1641940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                   handleSegOverride(sorb, mkU32(d)));
1642d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1643ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj         /*NOTREACHED*/
1644d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         vassert(0);
1645d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      }
1646d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1647d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* SIB, with 8-bit displacement.  Special cases:
1648d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         -- %esp cannot act as an index value.
1649d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            If index_r indicates %esp, zero is used for the index.
1650d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         Denoted value is:
1651d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            | %index == %ESP
1652d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            = d8 + %base
1653d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            | %index != %ESP
1654d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            = d8 + %base + (%index << scale)
1655d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      */
1656d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x0C: {
1657d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         UChar sib     = getIByte(delta);
16589b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar scale   = toUChar((sib >> 6) & 3);
16599b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar index_r = toUChar((sib >> 3) & 7);
16609b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar base_r  = toUChar(sib & 7);
1661d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         UInt  d       = getSDisp8(delta+1);
1662d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1663d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (index_r == R_ESP) {
16642d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj            DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
16652d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj                                   (Int)d, nameIReg(4,base_r));
16665bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 3;
16675bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            return disAMode_copy2tmp(
1668940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                   handleSegOverride(sorb,
1669940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                      binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
1670d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         } else {
16712d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj            DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1672d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                     nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
16735bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 3;
16745bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            return
1675940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                disAMode_copy2tmp(
1676940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                handleSegOverride(sorb,
167777b86be374085943e902075b305ff047a053aac6sewardj                  binop(Iop_Add32,
167877b86be374085943e902075b305ff047a053aac6sewardj                        binop(Iop_Add32,
167977b86be374085943e902075b305ff047a053aac6sewardj                              getIReg(4,base_r),
168077b86be374085943e902075b305ff047a053aac6sewardj                              binop(Iop_Shl32,
16816d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj                                    getIReg(4,index_r), mkU8(scale))),
1682940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                        mkU32(d))));
1683d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1684ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj	 /*NOTREACHED*/
1685d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         vassert(0);
1686d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      }
1687d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1688d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* SIB, with 32-bit displacement.  Special cases:
1689d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         -- %esp cannot act as an index value.
1690d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            If index_r indicates %esp, zero is used for the index.
1691d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         Denoted value is:
1692d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            | %index == %ESP
1693d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            = d32 + %base
1694d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            | %index != %ESP
1695d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            = d32 + %base + (%index << scale)
1696d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      */
1697d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x14: {
1698d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         UChar sib     = getIByte(delta);
16999b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar scale   = toUChar((sib >> 6) & 3);
17009b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar index_r = toUChar((sib >> 3) & 7);
17019b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar base_r  = toUChar(sib & 7);
1702d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         UInt d        = getUDisp32(delta+1);
1703d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1704d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (index_r == R_ESP) {
17052d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj            DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
17062d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj                                   (Int)d, nameIReg(4,base_r));
17075bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 6;
17085bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            return disAMode_copy2tmp(
1709940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                   handleSegOverride(sorb,
1710940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                      binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
1711d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         } else {
17122d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj            DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
17132d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj                     nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
17145bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 6;
17155bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            return
1716940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                disAMode_copy2tmp(
1717940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                handleSegOverride(sorb,
17189334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                  binop(Iop_Add32,
17199334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                        binop(Iop_Add32,
17209334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                              getIReg(4,base_r),
17219334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                              binop(Iop_Shl32,
17226d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj                                    getIReg(4,index_r), mkU8(scale))),
1723940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                        mkU32(d))));
1724d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1725ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj	 /*NOTREACHED*/
1726d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         vassert(0);
1727d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      }
1728d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1729d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      default:
1730d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         vpanic("disAMode(x86)");
1731d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         return 0; /*notreached*/
1732d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   }
1733d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
1734d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1735d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1736d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/* Figure out the number of (insn-stream) bytes constituting the amode
1737d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   beginning at delta.  Is useful for getting hold of literals beyond
1738d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   the end of the amode before it has been disassembled.  */
1739d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
174052d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt lengthAMode ( Int delta )
1741d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
1742d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   UChar mod_reg_rm = getIByte(delta); delta++;
1743d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1744d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1745d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      jump table seems a bit excessive.
1746d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   */
1747d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   mod_reg_rm &= 0xC7;               /* is now XX000YYY */
17489b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj   mod_reg_rm  = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
17499b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj                                     /* is now XX0XXYYY */
1750d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   mod_reg_rm &= 0x1F;               /* is now 000XXYYY */
1751d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   switch (mod_reg_rm) {
1752d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1753d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1754d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x00: case 0x01: case 0x02: case 0x03:
1755d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1756d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         return 1;
1757d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1758d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1759d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x08: case 0x09: case 0x0A: case 0x0B:
1760d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1761d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         return 2;
1762d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1763d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1764d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x10: case 0x11: case 0x12: case 0x13:
1765d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* ! 14 */ case 0x15: case 0x16: case 0x17:
1766d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         return 5;
1767d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1768d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* a register, %eax .. %edi.  (Not an addr, but still handled.) */
1769d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x18: case 0x19: case 0x1A: case 0x1B:
1770d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1771d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         return 1;
1772d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1773d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* a 32-bit literal address. */
1774d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x05: return 5;
1775d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1776d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* SIB, no displacement.  */
1777d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x04: {
1778d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         UChar sib    = getIByte(delta);
17799b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar base_r = toUChar(sib & 7);
1780d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (base_r == R_EBP) return 6; else return 2;
1781d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      }
1782d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* SIB, with 8-bit displacement.  */
1783d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x0C: return 3;
1784d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1785d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* SIB, with 32-bit displacement.  */
1786d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x14: return 6;
1787d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1788d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      default:
1789d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         vpanic("lengthAMode");
1790d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         return 0; /*notreached*/
1791d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   }
1792d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
1793d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1794d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/*------------------------------------------------------------*/
1795d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/*--- Disassembling common idioms                          ---*/
1796d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/*------------------------------------------------------------*/
1797c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
1798e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj/* Handle binary integer instructions of the form
1799e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      op E, G  meaning
1800e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      op reg-or-mem, reg
1801e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   Is passed the a ptr to the modRM byte, the actual operation, and the
1802e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   data size.  Returns the address advanced completely over this
1803e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   instruction.
1804e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1805e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   E(src) is reg-or-mem
1806e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   G(dst) is reg.
1807e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1808e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   If E is reg, -->    GET %G,  tmp
1809e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       OP %E,   tmp
1810e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       PUT tmp, %G
1811e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1812e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   If E is mem and OP is not reversible,
1813e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                -->    (getAddr E) -> tmpa
1814e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       LD (tmpa), tmpa
1815e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       GET %G, tmp2
1816e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       OP tmpa, tmp2
1817e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       PUT tmp2, %G
1818e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1819e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   If E is mem and OP is reversible
1820e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                -->    (getAddr E) -> tmpa
1821e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       LD (tmpa), tmpa
1822e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       OP %G, tmpa
1823e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       PUT tmpa, %G
1824e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj*/
1825e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardjstatic
1826e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardjUInt dis_op2_E_G ( UChar       sorb,
1827180e8b39d5b4271e64634162986749c43536647csewardj                   Bool        addSubCarry,
1828e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                   IROp        op8,
1829e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                   Bool        keep,
1830e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                   Int         size,
183152d049186d07991237a825ec88aa7f1f303edb70sewardj                   Int         delta0,
183255085f8680acc89d727e321f3b34cae1a8c4093aflorian                   const HChar* t_x86opc )
1833e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj{
1834c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar   dis_buf[50];
18359334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   Int     len;
1836e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   IRType  ty   = szToITy(size);
1837e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   IRTemp  dst1 = newTemp(ty);
1838e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   IRTemp  src  = newTemp(ty);
1839e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   IRTemp  dst0 = newTemp(ty);
1840e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   UChar   rm   = getUChar(delta0);
184192d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp  addr = IRTemp_INVALID;
1842e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1843180e8b39d5b4271e64634162986749c43536647csewardj   /* addSubCarry == True indicates the intended operation is
1844180e8b39d5b4271e64634162986749c43536647csewardj      add-with-carry or subtract-with-borrow. */
1845180e8b39d5b4271e64634162986749c43536647csewardj   if (addSubCarry) {
1846180e8b39d5b4271e64634162986749c43536647csewardj      vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1847180e8b39d5b4271e64634162986749c43536647csewardj      vassert(keep);
1848180e8b39d5b4271e64634162986749c43536647csewardj   }
1849180e8b39d5b4271e64634162986749c43536647csewardj
1850e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   if (epartIsReg(rm)) {
1851e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      /* Specially handle XOR reg,reg, because that doesn't really
1852e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj         depend on reg, and doing the obvious thing potentially
1853e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj         generates a spurious value check failure due to the bogus
185455efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj         dependency.  Ditto SBB reg,reg. */
185555efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj      if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
185655efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj          && gregOfRM(rm) == eregOfRM(rm)) {
185755efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj         putIReg(size, gregOfRM(rm), mkU(ty,0));
1858e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      }
1859e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      assign( dst0, getIReg(size,gregOfRM(rm)) );
1860e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      assign( src,  getIReg(size,eregOfRM(rm)) );
1861e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1862180e8b39d5b4271e64634162986749c43536647csewardj      if (addSubCarry && op8 == Iop_Add8) {
1863e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_ADC( size, dst1, dst0, src,
1864e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1865e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1866180e8b39d5b4271e64634162986749c43536647csewardj      } else
1867180e8b39d5b4271e64634162986749c43536647csewardj      if (addSubCarry && op8 == Iop_Sub8) {
1868e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_SBB( size, dst1, dst0, src,
1869e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1870180e8b39d5b4271e64634162986749c43536647csewardj         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1871180e8b39d5b4271e64634162986749c43536647csewardj      } else {
1872180e8b39d5b4271e64634162986749c43536647csewardj         assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
18735bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         if (isAddSub(op8))
18742a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(op8, dst0, src, ty);
1875b9c5cf639b3b21b972599d27207a033afc76ef67sewardj         else
18762a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1(op8, dst1, ty);
1877180e8b39d5b4271e64634162986749c43536647csewardj         if (keep)
1878180e8b39d5b4271e64634162986749c43536647csewardj            putIReg(size, gregOfRM(rm), mkexpr(dst1));
1879180e8b39d5b4271e64634162986749c43536647csewardj      }
1880e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1881e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1882e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                          nameIReg(size,eregOfRM(rm)),
1883e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                          nameIReg(size,gregOfRM(rm)));
1884e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      return 1+delta0;
1885e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   } else {
18869334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      /* E refers to memory */
18879334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      addr = disAMode ( &len, sorb, delta0, dis_buf);
18889334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      assign( dst0, getIReg(size,gregOfRM(rm)) );
1889940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      assign( src,  loadLE(szToITy(size), mkexpr(addr)) );
18909334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
1891180e8b39d5b4271e64634162986749c43536647csewardj      if (addSubCarry && op8 == Iop_Add8) {
1892e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_ADC( size, dst1, dst0, src,
1893e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1894180e8b39d5b4271e64634162986749c43536647csewardj         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1895180e8b39d5b4271e64634162986749c43536647csewardj      } else
1896180e8b39d5b4271e64634162986749c43536647csewardj      if (addSubCarry && op8 == Iop_Sub8) {
1897e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_SBB( size, dst1, dst0, src,
1898e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
18999334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1900180e8b39d5b4271e64634162986749c43536647csewardj      } else {
1901180e8b39d5b4271e64634162986749c43536647csewardj         assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
19025bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         if (isAddSub(op8))
19032a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(op8, dst0, src, ty);
1904b9c5cf639b3b21b972599d27207a033afc76ef67sewardj         else
19052a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1(op8, dst1, ty);
1906180e8b39d5b4271e64634162986749c43536647csewardj         if (keep)
1907180e8b39d5b4271e64634162986749c43536647csewardj            putIReg(size, gregOfRM(rm), mkexpr(dst1));
1908180e8b39d5b4271e64634162986749c43536647csewardj      }
19099334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
1910e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1911e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                          dis_buf,nameIReg(size,gregOfRM(rm)));
19129334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      return len+delta0;
1913e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   }
1914e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj}
1915e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1916e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1917e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1918e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj/* Handle binary integer instructions of the form
1919e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      op G, E  meaning
1920e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      op reg, reg-or-mem
1921e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   Is passed the a ptr to the modRM byte, the actual operation, and the
1922e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   data size.  Returns the address advanced completely over this
1923e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   instruction.
1924e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1925e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   G(src) is reg.
1926e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   E(dst) is reg-or-mem
1927e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1928e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   If E is reg, -->    GET %E,  tmp
1929e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       OP %G,   tmp
1930e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       PUT tmp, %E
1931e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1932e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   If E is mem, -->    (getAddr E) -> tmpa
1933e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       LD (tmpa), tmpv
1934e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       OP %G, tmpv
1935e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       ST tmpv, (tmpa)
1936e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj*/
1937e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjstatic
1938e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjUInt dis_op2_G_E ( UChar       sorb,
1939e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                   Bool        locked,
1940caca9d0d3729c36af6ae02b0654cb289101248cbsewardj                   Bool        addSubCarry,
1941e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                   IROp        op8,
1942e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                   Bool        keep,
1943e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                   Int         size,
194452d049186d07991237a825ec88aa7f1f303edb70sewardj                   Int         delta0,
194555085f8680acc89d727e321f3b34cae1a8c4093aflorian                   const HChar* t_x86opc )
1946e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj{
1947c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar   dis_buf[50];
1948e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   Int     len;
1949e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRType  ty   = szToITy(size);
1950e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRTemp  dst1 = newTemp(ty);
1951e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRTemp  src  = newTemp(ty);
1952e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRTemp  dst0 = newTemp(ty);
1953e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   UChar   rm   = getIByte(delta0);
195492d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp  addr = IRTemp_INVALID;
1955e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1956caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   /* addSubCarry == True indicates the intended operation is
1957caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      add-with-carry or subtract-with-borrow. */
1958caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   if (addSubCarry) {
1959caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1960caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      vassert(keep);
1961caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   }
1962caca9d0d3729c36af6ae02b0654cb289101248cbsewardj
1963e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   if (epartIsReg(rm)) {
1964e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      /* Specially handle XOR reg,reg, because that doesn't really
1965e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj         depend on reg, and doing the obvious thing potentially
1966e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj         generates a spurious value check failure due to the bogus
196755efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj         dependency.  Ditto SBB reg,reg.*/
196855efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj      if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
196955efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj          && gregOfRM(rm) == eregOfRM(rm)) {
197055efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj         putIReg(size, eregOfRM(rm), mkU(ty,0));
1971e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      }
1972e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      assign(dst0, getIReg(size,eregOfRM(rm)));
1973e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      assign(src,  getIReg(size,gregOfRM(rm)));
1974e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1975caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      if (addSubCarry && op8 == Iop_Add8) {
1976e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_ADC( size, dst1, dst0, src,
1977e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
19781813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         putIReg(size, eregOfRM(rm), mkexpr(dst1));
1979caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      } else
1980caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      if (addSubCarry && op8 == Iop_Sub8) {
1981e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_SBB( size, dst1, dst0, src,
1982e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1983e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj         putIReg(size, eregOfRM(rm), mkexpr(dst1));
1984caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      } else {
1985caca9d0d3729c36af6ae02b0654cb289101248cbsewardj         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
19865bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         if (isAddSub(op8))
19872a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(op8, dst0, src, ty);
1988b9c5cf639b3b21b972599d27207a033afc76ef67sewardj         else
19892a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1(op8, dst1, ty);
1990caca9d0d3729c36af6ae02b0654cb289101248cbsewardj         if (keep)
1991caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            putIReg(size, eregOfRM(rm), mkexpr(dst1));
1992caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      }
1993e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1994e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1995e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                          nameIReg(size,gregOfRM(rm)),
1996e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                          nameIReg(size,eregOfRM(rm)));
1997e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      return 1+delta0;
1998e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   }
1999e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2000e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   /* E refers to memory */
2001e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   {
2002e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      addr = disAMode ( &len, sorb, delta0, dis_buf);
2003940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      assign(dst0, loadLE(ty,mkexpr(addr)));
2004e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      assign(src,  getIReg(size,gregOfRM(rm)));
2005e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
2006caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      if (addSubCarry && op8 == Iop_Add8) {
2007e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (locked) {
2008e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* cas-style store */
2009e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_ADC( size, dst1, dst0, src,
2010e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                        /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2011e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         } else {
2012e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* normal store */
2013e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_ADC( size, dst1, dst0, src,
2014e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                        /*store*/addr, IRTemp_INVALID, 0 );
2015e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
2016caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      } else
2017caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      if (addSubCarry && op8 == Iop_Sub8) {
2018e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (locked) {
2019e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* cas-style store */
2020e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_SBB( size, dst1, dst0, src,
2021e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                        /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2022e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         } else {
2023e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* normal store */
2024e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_SBB( size, dst1, dst0, src,
2025e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                        /*store*/addr, IRTemp_INVALID, 0 );
2026e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
2027caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      } else {
2028caca9d0d3729c36af6ae02b0654cb289101248cbsewardj         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2029e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (keep) {
2030e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
2031e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (0) vex_printf("locked case\n" );
2032e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr),
2033e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                      mkexpr(dst0)/*expval*/,
2034e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                      mkexpr(dst1)/*newval*/, guest_EIP_curr_instr );
2035e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
2036e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (0) vex_printf("nonlocked case\n");
2037e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE(mkexpr(addr), mkexpr(dst1));
2038e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
2039e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
20405bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         if (isAddSub(op8))
20412a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2042b9c5cf639b3b21b972599d27207a033afc76ef67sewardj         else
20432a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1(op8, dst1, ty);
2044caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      }
2045e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2046e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2047e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                          nameIReg(size,gregOfRM(rm)), dis_buf);
2048e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      return len+delta0;
2049e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   }
2050e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj}
2051e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2052e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2053e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj/* Handle move instructions of the form
2054e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      mov E, G  meaning
2055e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      mov reg-or-mem, reg
2056e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   Is passed the a ptr to the modRM byte, and the data size.  Returns
2057e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   the address advanced completely over this instruction.
2058e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2059e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   E(src) is reg-or-mem
2060e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   G(dst) is reg.
2061e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2062e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   If E is reg, -->    GET %E,  tmpv
2063e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       PUT tmpv, %G
2064e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2065e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   If E is mem  -->    (getAddr E) -> tmpa
2066e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       LD (tmpa), tmpb
2067e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       PUT tmpb, %G
2068e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj*/
2069e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjstatic
2070e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjUInt dis_mov_E_G ( UChar       sorb,
2071e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                   Int         size,
207252d049186d07991237a825ec88aa7f1f303edb70sewardj                   Int         delta0 )
2073e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj{
2074e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   Int len;
2075e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   UChar rm = getIByte(delta0);
2076c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
2077e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2078e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   if (epartIsReg(rm)) {
20797ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj      putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
2080e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      DIP("mov%c %s,%s\n", nameISize(size),
2081e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                           nameIReg(size,eregOfRM(rm)),
2082e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                           nameIReg(size,gregOfRM(rm)));
20837ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj      return 1+delta0;
2084e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   }
2085e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2086e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   /* E refers to memory */
2087e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   {
2088940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
2089940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
2090e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      DIP("mov%c %s,%s\n", nameISize(size),
2091e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                           dis_buf,nameIReg(size,gregOfRM(rm)));
2092e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      return delta0+len;
2093e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   }
2094e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj}
2095e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2096e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2097e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj/* Handle move instructions of the form
2098e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      mov G, E  meaning
2099e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      mov reg, reg-or-mem
2100e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   Is passed the a ptr to the modRM byte, and the data size.  Returns
2101e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   the address advanced completely over this instruction.
2102e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2103e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   G(src) is reg.
2104e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   E(dst) is reg-or-mem
2105e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2106e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   If E is reg, -->    GET %G,  tmp
2107e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       PUT tmp, %E
2108e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2109e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   If E is mem, -->    (getAddr E) -> tmpa
2110e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       GET %G, tmpv
2111e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       ST tmpv, (tmpa)
2112e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj*/
2113c9a6570e86f4252f8a486b4df48de8710d357a4asewardjstatic
2114c9a6570e86f4252f8a486b4df48de8710d357a4asewardjUInt dis_mov_G_E ( UChar       sorb,
2115c9a6570e86f4252f8a486b4df48de8710d357a4asewardj                   Int         size,
211652d049186d07991237a825ec88aa7f1f303edb70sewardj                   Int         delta0 )
2117c9a6570e86f4252f8a486b4df48de8710d357a4asewardj{
2118e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   Int len;
2119c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   UChar rm = getIByte(delta0);
2120c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
2121c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
2122c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   if (epartIsReg(rm)) {
212341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
2124c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      DIP("mov%c %s,%s\n", nameISize(size),
2125c9a6570e86f4252f8a486b4df48de8710d357a4asewardj                           nameIReg(size,gregOfRM(rm)),
2126c9a6570e86f4252f8a486b4df48de8710d357a4asewardj                           nameIReg(size,eregOfRM(rm)));
2127c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      return 1+delta0;
2128c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   }
2129c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
2130c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* E refers to memory */
2131c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   {
2132940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
2133940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
2134c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      DIP("mov%c %s,%s\n", nameISize(size),
2135c9a6570e86f4252f8a486b4df48de8710d357a4asewardj                           nameIReg(size,gregOfRM(rm)), dis_buf);
2136e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      return len+delta0;
2137c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   }
2138c9a6570e86f4252f8a486b4df48de8710d357a4asewardj}
2139c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
2140c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
21410611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj/* op $immediate, AL/AX/EAX. */
21420611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardjstatic
21430611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardjUInt dis_op_imm_A ( Int    size,
2144a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj                    Bool   carrying,
21450611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                    IROp   op8,
21460611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                    Bool   keep,
214752d049186d07991237a825ec88aa7f1f303edb70sewardj                    Int    delta,
214855085f8680acc89d727e321f3b34cae1a8c4093aflorian                    const HChar* t_x86opc )
21490611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj{
21500611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   IRType ty   = szToITy(size);
21510611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   IRTemp dst0 = newTemp(ty);
21520611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   IRTemp src  = newTemp(ty);
21530611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   IRTemp dst1 = newTemp(ty);
21540611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   UInt lit    = getUDisp(size,delta);
21550611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   assign(dst0, getIReg(size,R_EAX));
21560611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   assign(src,  mkU(ty,lit));
2157a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj
2158a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   if (isAddSub(op8) && !carrying) {
2159a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
21602a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      setFlags_DEP1_DEP2(op8, dst0, src, ty);
2161a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   }
2162b9c5cf639b3b21b972599d27207a033afc76ef67sewardj   else
2163a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   if (isLogic(op8)) {
2164a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      vassert(!carrying);
2165a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
21662a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      setFlags_DEP1(op8, dst1, ty);
2167a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   }
2168a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   else
2169a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   if (op8 == Iop_Add8 && carrying) {
2170e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      helper_ADC( size, dst1, dst0, src,
2171e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2172a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   }
21732a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   else
21742fbae083dad486e8e623011b4dd68ba204c2a228sewardj   if (op8 == Iop_Sub8 && carrying) {
2175e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      helper_SBB( size, dst1, dst0, src,
2176e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
21772fbae083dad486e8e623011b4dd68ba204c2a228sewardj   }
21782fbae083dad486e8e623011b4dd68ba204c2a228sewardj   else
21792a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      vpanic("dis_op_imm_A(x86,guest)");
21800611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
21810611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   if (keep)
21820611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      putIReg(size, R_EAX, mkexpr(dst1));
21830611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
21840611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
21850611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                           lit, nameIReg(size,R_EAX));
21860611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   return delta+size;
21870611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj}
21889334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
21899334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
21909334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj/* Sign- and Zero-extending moves. */
21919334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardjstatic
219252d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_movx_E_G ( UChar      sorb,
219352d049186d07991237a825ec88aa7f1f303edb70sewardj                    Int delta, Int szs, Int szd, Bool sign_extend )
21949334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj{
21959334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   UChar rm = getIByte(delta);
21969334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   if (epartIsReg(rm)) {
219733ca4acf01e29bf8ec4adce63aa5925d549c105esewardj      if (szd == szs) {
219833ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         // mutant case.  See #250799
219933ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         putIReg(szd, gregOfRM(rm),
220033ca4acf01e29bf8ec4adce63aa5925d549c105esewardj                           getIReg(szs,eregOfRM(rm)));
220133ca4acf01e29bf8ec4adce63aa5925d549c105esewardj      } else {
220233ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         // normal case
220333ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         putIReg(szd, gregOfRM(rm),
220433ca4acf01e29bf8ec4adce63aa5925d549c105esewardj                      unop(mkWidenOp(szs,szd,sign_extend),
220533ca4acf01e29bf8ec4adce63aa5925d549c105esewardj                           getIReg(szs,eregOfRM(rm))));
220633ca4acf01e29bf8ec4adce63aa5925d549c105esewardj      }
22079334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
22089334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                               nameISize(szs), nameISize(szd),
22099334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                               nameIReg(szs,eregOfRM(rm)),
22109334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                               nameIReg(szd,gregOfRM(rm)));
22119334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      return 1+delta;
22129334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   }
22139334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
22149334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   /* E refers to memory */
22159334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   {
2216940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      Int    len;
2217c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      HChar  dis_buf[50];
2218940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
221933ca4acf01e29bf8ec4adce63aa5925d549c105esewardj      if (szd == szs) {
222033ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         // mutant case.  See #250799
222133ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         putIReg(szd, gregOfRM(rm),
222233ca4acf01e29bf8ec4adce63aa5925d549c105esewardj                           loadLE(szToITy(szs),mkexpr(addr)));
222333ca4acf01e29bf8ec4adce63aa5925d549c105esewardj      } else {
222433ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         // normal case
222533ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         putIReg(szd, gregOfRM(rm),
222633ca4acf01e29bf8ec4adce63aa5925d549c105esewardj                      unop(mkWidenOp(szs,szd,sign_extend),
222733ca4acf01e29bf8ec4adce63aa5925d549c105esewardj                           loadLE(szToITy(szs),mkexpr(addr))));
222833ca4acf01e29bf8ec4adce63aa5925d549c105esewardj      }
22299334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
22309334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                               nameISize(szs), nameISize(szd),
22319334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                               dis_buf, nameIReg(szd,gregOfRM(rm)));
22320611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      return len+delta;
22339334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   }
22349334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj}
22359334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
22369690d927540d730525a5f7f14663f3ceaa7818dasewardj
22379690d927540d730525a5f7f14663f3ceaa7818dasewardj/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
22389690d927540d730525a5f7f14663f3ceaa7818dasewardj   16 / 8 bit quantity in the given IRTemp.  */
22399690d927540d730525a5f7f14663f3ceaa7818dasewardjstatic
22409690d927540d730525a5f7f14663f3ceaa7818dasewardjvoid codegen_div ( Int sz, IRTemp t, Bool signed_divide )
22419690d927540d730525a5f7f14663f3ceaa7818dasewardj{
2242e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj   IROp   op    = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2243e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj   IRTemp src64 = newTemp(Ity_I64);
2244e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj   IRTemp dst64 = newTemp(Ity_I64);
22459690d927540d730525a5f7f14663f3ceaa7818dasewardj   switch (sz) {
2246e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj      case 4:
22479690d927540d730525a5f7f14663f3ceaa7818dasewardj         assign( src64, binop(Iop_32HLto64,
2248e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj                              getIReg(4,R_EDX), getIReg(4,R_EAX)) );
22499690d927540d730525a5f7f14663f3ceaa7818dasewardj         assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
22508c7f1abe9e022f6382634efea09c9cac89ec6336sewardj         putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
22519690d927540d730525a5f7f14663f3ceaa7818dasewardj         putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
22529690d927540d730525a5f7f14663f3ceaa7818dasewardj         break;
2253e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj      case 2: {
2254e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2255e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2256e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         assign( src64, unop(widen3264,
2257e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj                             binop(Iop_16HLto32,
2258e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj                                   getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2259e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2260e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2261e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2262e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         break;
22639690d927540d730525a5f7f14663f3ceaa7818dasewardj      }
22644e82db7b7141106436f7f543c30050f80fcc9933sewardj      case 1: {
22654e82db7b7141106436f7f543c30050f80fcc9933sewardj         IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
22664e82db7b7141106436f7f543c30050f80fcc9933sewardj         IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
22674e82db7b7141106436f7f543c30050f80fcc9933sewardj         IROp widen816  = signed_divide ? Iop_8Sto16  : Iop_8Uto16;
22684e82db7b7141106436f7f543c30050f80fcc9933sewardj         assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
22694e82db7b7141106436f7f543c30050f80fcc9933sewardj         assign( dst64,
22704e82db7b7141106436f7f543c30050f80fcc9933sewardj                 binop(op, mkexpr(src64),
22714e82db7b7141106436f7f543c30050f80fcc9933sewardj                           unop(widen1632, unop(widen816, mkexpr(t)))) );
22724e82db7b7141106436f7f543c30050f80fcc9933sewardj         putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
22734e82db7b7141106436f7f543c30050f80fcc9933sewardj                           unop(Iop_64to32,mkexpr(dst64)))) );
22744e82db7b7141106436f7f543c30050f80fcc9933sewardj         putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
22754e82db7b7141106436f7f543c30050f80fcc9933sewardj                           unop(Iop_64HIto32,mkexpr(dst64)))) );
22764e82db7b7141106436f7f543c30050f80fcc9933sewardj         break;
22774e82db7b7141106436f7f543c30050f80fcc9933sewardj      }
22789690d927540d730525a5f7f14663f3ceaa7818dasewardj      default: vpanic("codegen_div(x86)");
22799690d927540d730525a5f7f14663f3ceaa7818dasewardj   }
22809690d927540d730525a5f7f14663f3ceaa7818dasewardj}
228141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
228241f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
228341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardjstatic
2284e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardjUInt dis_Grp1 ( UChar sorb, Bool locked,
228552d049186d07991237a825ec88aa7f1f303edb70sewardj                Int delta, UChar modrm,
228641f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj                Int am_sz, Int d_sz, Int sz, UInt d32 )
228741f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj{
228841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   Int     len;
2289c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar   dis_buf[50];
2290e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRType  ty   = szToITy(sz);
2291e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRTemp  dst1 = newTemp(ty);
2292e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRTemp  src  = newTemp(ty);
2293e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRTemp  dst0 = newTemp(ty);
229492d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp  addr = IRTemp_INVALID;
229566de22767fc526eff52133c18d4a42a9b25d5f18sewardj   IROp    op8  = Iop_INVALID;
2296180e8b39d5b4271e64634162986749c43536647csewardj   UInt    mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
229741f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
229841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   switch (gregOfRM(modrm)) {
2299e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      case 0: op8 = Iop_Add8; break;  case 1: op8 = Iop_Or8;  break;
230066de22767fc526eff52133c18d4a42a9b25d5f18sewardj      case 2: break;  // ADC
230166de22767fc526eff52133c18d4a42a9b25d5f18sewardj      case 3: break;  // SBB
2302e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      case 4: op8 = Iop_And8; break;  case 5: op8 = Iop_Sub8; break;
2303e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      case 6: op8 = Iop_Xor8; break;  case 7: op8 = Iop_Sub8; break;
2304d51dc81599cba69ddc133f56c743205330f9dc40sewardj      /*NOTREACHED*/
230541f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      default: vpanic("dis_Grp1: unhandled case");
230641f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   }
230741f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
230841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   if (epartIsReg(modrm)) {
230941f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      vassert(am_sz == 1);
231041f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
231141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      assign(dst0, getIReg(sz,eregOfRM(modrm)));
2312180e8b39d5b4271e64634162986749c43536647csewardj      assign(src,  mkU(ty,d32 & mask));
231341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
2314180e8b39d5b4271e64634162986749c43536647csewardj      if (gregOfRM(modrm) == 2 /* ADC */) {
2315e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_ADC( sz, dst1, dst0, src,
2316e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2317180e8b39d5b4271e64634162986749c43536647csewardj      } else
2318180e8b39d5b4271e64634162986749c43536647csewardj      if (gregOfRM(modrm) == 3 /* SBB */) {
2319e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_SBB( sz, dst1, dst0, src,
2320e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2321180e8b39d5b4271e64634162986749c43536647csewardj      } else {
2322180e8b39d5b4271e64634162986749c43536647csewardj         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
23235bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         if (isAddSub(op8))
23242a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2325b9c5cf639b3b21b972599d27207a033afc76ef67sewardj         else
23262a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1(op8, dst1, ty);
2327180e8b39d5b4271e64634162986749c43536647csewardj      }
232841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
232941f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      if (gregOfRM(modrm) < 7)
2330e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj         putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
233141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
233241f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      delta += (am_sz + d_sz);
233341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
233441f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj                              nameIReg(sz,eregOfRM(modrm)));
233541f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   } else {
2336e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      addr = disAMode ( &len, sorb, delta, dis_buf);
233741f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
2338940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      assign(dst0, loadLE(ty,mkexpr(addr)));
2339180e8b39d5b4271e64634162986749c43536647csewardj      assign(src, mkU(ty,d32 & mask));
234041f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
234166de22767fc526eff52133c18d4a42a9b25d5f18sewardj      if (gregOfRM(modrm) == 2 /* ADC */) {
2342e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (locked) {
2343e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* cas-style store */
2344e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_ADC( sz, dst1, dst0, src,
2345e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                       /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2346e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         } else {
2347e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* normal store */
2348e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_ADC( sz, dst1, dst0, src,
2349e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                        /*store*/addr, IRTemp_INVALID, 0 );
2350e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
23513af115ff8c215db41dff92da266a036c59eaec95sewardj      } else
235266de22767fc526eff52133c18d4a42a9b25d5f18sewardj      if (gregOfRM(modrm) == 3 /* SBB */) {
2353e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (locked) {
2354e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* cas-style store */
2355e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_SBB( sz, dst1, dst0, src,
2356e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                       /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2357e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         } else {
2358e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* normal store */
2359e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_SBB( sz, dst1, dst0, src,
2360e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                        /*store*/addr, IRTemp_INVALID, 0 );
2361e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
23623af115ff8c215db41dff92da266a036c59eaec95sewardj      } else {
23633af115ff8c215db41dff92da266a036c59eaec95sewardj         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2364e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (gregOfRM(modrm) < 7) {
2365e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
2366e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr), mkexpr(dst0)/*expVal*/,
2367e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                    mkexpr(dst1)/*newVal*/,
2368e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                    guest_EIP_curr_instr );
2369e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
2370e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE(mkexpr(addr), mkexpr(dst1));
2371e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
2372e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
23735bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         if (isAddSub(op8))
23742a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2375b9c5cf639b3b21b972599d27207a033afc76ef67sewardj         else
23762a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1(op8, dst1, ty);
23773af115ff8c215db41dff92da266a036c59eaec95sewardj      }
237841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
237941f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      delta += (len+d_sz);
238041f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
238141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj                              d32, dis_buf);
238241f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   }
238341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   return delta;
238441f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj}
238541f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
238641f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
23876d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj/* Group 2 extended opcodes.  shift_expr must be an 8-bit typed
23886d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   expression. */
23896d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj
2390e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardjstatic
239152d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_Grp2 ( UChar sorb,
239252d049186d07991237a825ec88aa7f1f303edb70sewardj                Int delta, UChar modrm,
23936d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj                Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
239455085f8680acc89d727e321f3b34cae1a8c4093aflorian                const HChar* shift_expr_txt, Bool* decode_OK )
2395e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj{
2396e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   /* delta on entry points at the modrm byte. */
2397c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar  dis_buf[50];
23986d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   Int    len;
23992eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj   Bool   isShift, isRotate, isRotateC;
24006d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRType ty    = szToITy(sz);
24016d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp dst0  = newTemp(ty);
24026d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp dst1  = newTemp(ty);
240392d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp addr  = IRTemp_INVALID;
2404e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2405d51dc81599cba69ddc133f56c743205330f9dc40sewardj   *decode_OK = True;
2406d51dc81599cba69ddc133f56c743205330f9dc40sewardj
2407e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   vassert(sz == 1 || sz == 2 || sz == 4);
2408e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2409e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   /* Put value to shift/rotate in dst0. */
2410e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   if (epartIsReg(modrm)) {
2411e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      assign(dst0, getIReg(sz, eregOfRM(modrm)));
2412940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      delta += (am_sz + d_sz);
2413e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   } else {
2414940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      addr = disAMode ( &len, sorb, delta, dis_buf);
2415940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      assign(dst0, loadLE(ty,mkexpr(addr)));
2416940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      delta += len + d_sz;
2417e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   }
2418e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2419e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   isShift = False;
2420d6b43fd4fcdb151c3fefb213de4dd64f8bb247b3tom   switch (gregOfRM(modrm)) { case 4: case 5: case 6: case 7: isShift = True; }
2421e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2422750f407b6be1aac303964a219acf0a6de8b8c4dasewardj   isRotate = False;
2423750f407b6be1aac303964a219acf0a6de8b8c4dasewardj   switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2424750f407b6be1aac303964a219acf0a6de8b8c4dasewardj
24252eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj   isRotateC = False;
24262eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj   switch (gregOfRM(modrm)) { case 2: case 3: isRotateC = True; }
24279aebb0c3f7a7f43313786826f31402f2b733badfsewardj
24282eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj   if (!isShift && !isRotate && !isRotateC) {
2429d51dc81599cba69ddc133f56c743205330f9dc40sewardj      /*NOTREACHED*/
24308c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      vpanic("dis_Grp2(Reg): unhandled case(x86)");
24318c7f1abe9e022f6382634efea09c9cac89ec6336sewardj   }
24328c7f1abe9e022f6382634efea09c9cac89ec6336sewardj
24332eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj   if (isRotateC) {
24342eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj      /* call a helper; these insns are so ridiculous they do not
24352eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj         deserve better */
24362eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj      Bool     left = toBool(gregOfRM(modrm) == 2);
24379aebb0c3f7a7f43313786826f31402f2b733badfsewardj      IRTemp   r64  = newTemp(Ity_I64);
2438f96552617c82834ece36184e674e249faa899b2fsewardj      IRExpr** args
2439f96552617c82834ece36184e674e249faa899b2fsewardj         = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2440f96552617c82834ece36184e674e249faa899b2fsewardj                          widenUto32(shift_expr),   /* rotate amount */
24412a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                          widenUto32(mk_x86g_calculate_eflags_all()),
2442f96552617c82834ece36184e674e249faa899b2fsewardj                          mkU32(sz) );
2443f96552617c82834ece36184e674e249faa899b2fsewardj      assign( r64, mkIRExprCCall(
24448ea867b06de73d909c29e243407713c291c8414esewardj                      Ity_I64,
2445f96552617c82834ece36184e674e249faa899b2fsewardj                      0/*regparm*/,
24462eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj                      left ? "x86g_calculate_RCL" : "x86g_calculate_RCR",
24472eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj                      left ? &x86g_calculate_RCL  : &x86g_calculate_RCR,
24488ea867b06de73d909c29e243407713c291c8414esewardj                      args
2449f96552617c82834ece36184e674e249faa899b2fsewardj                   )
2450f96552617c82834ece36184e674e249faa899b2fsewardj            );
24519aebb0c3f7a7f43313786826f31402f2b733badfsewardj      /* new eflags in hi half r64; new value in lo half r64 */
24529aebb0c3f7a7f43313786826f31402f2b733badfsewardj      assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
24532a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
24542a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
24552a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2456a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      /* Set NDEP even though it isn't used.  This makes redundant-PUT
2457a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj         elimination of previous stores to this field work better. */
2458a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
24599aebb0c3f7a7f43313786826f31402f2b733badfsewardj   }
24609aebb0c3f7a7f43313786826f31402f2b733badfsewardj
2461e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   if (isShift) {
2462e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2463c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      IRTemp pre32     = newTemp(Ity_I32);
2464c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      IRTemp res32     = newTemp(Ity_I32);
2465c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      IRTemp res32ss   = newTemp(Ity_I32);
24666d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj      IRTemp shift_amt = newTemp(Ity_I8);
2467c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      IROp   op32;
2468e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2469e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      switch (gregOfRM(modrm)) {
2470c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         case 4: op32 = Iop_Shl32; break;
2471c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         case 5: op32 = Iop_Shr32; break;
2472d6b43fd4fcdb151c3fefb213de4dd64f8bb247b3tom         case 6: op32 = Iop_Shl32; break;
2473c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         case 7: op32 = Iop_Sar32; break;
2474d51dc81599cba69ddc133f56c743205330f9dc40sewardj         /*NOTREACHED*/
2475e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj         default: vpanic("dis_Grp2:shift"); break;
2476e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      }
2477e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2478c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* Widen the value to be shifted to 32 bits, do the shift, and
2479c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         narrow back down.  This seems surprisingly long-winded, but
2480c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         unfortunately the Intel semantics requires that 8/16-bit
2481c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         shifts give defined results for shift values all the way up
2482c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         to 31, and this seems the simplest way to do it.  It has the
2483c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         advantage that the only IR level shifts generated are of 32
2484c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         bit values, and the shift amount is guaranteed to be in the
2485c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         range 0 .. 31, thereby observing the IR semantics requiring
2486c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         all shift values to be in the range 0 .. 2^word_size-1. */
2487c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
2488c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* shift_amt = shift_expr & 31, regardless of operation size */
2489c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2490c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
2491c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* suitably widen the value to be shifted to 32 bits. */
2492c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2493c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj                                     : widenUto32(mkexpr(dst0)) );
2494c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
2495c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* res32 = pre32 `shift` shift_amt */
2496c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2497c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
2498c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2499c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      assign( res32ss,
2500c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj              binop(op32,
2501c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj                    mkexpr(pre32),
2502c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj                    binop(Iop_And8,
2503c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj                          binop(Iop_Sub8,
2504c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj                                mkexpr(shift_amt), mkU8(1)),
2505c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj                          mkU8(31))) );
2506e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2507e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      /* Build the flags thunk. */
25082a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
2509c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
2510c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* Narrow the result back down. */
2511c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      assign( dst1, narrowTo(ty, mkexpr(res32)) );
2512750f407b6be1aac303964a219acf0a6de8b8c4dasewardj
25131813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   } /* if (isShift) */
25141813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
25151813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   else
2516750f407b6be1aac303964a219acf0a6de8b8c4dasewardj   if (isRotate) {
25177ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      Int    ccOp      = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
25182d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool   left      = toBool(gregOfRM(modrm) == 0);
25197ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      IRTemp rot_amt   = newTemp(Ity_I8);
25207ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      IRTemp rot_amt32 = newTemp(Ity_I8);
25217ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      IRTemp oldFlags  = newTemp(Ity_I32);
2522750f407b6be1aac303964a219acf0a6de8b8c4dasewardj
2523750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      /* rot_amt = shift_expr & mask */
2524c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* By masking the rotate amount thusly, the IR-level Shl/Shr
2525c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         expressions never shift beyond the word size and thus remain
2526c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         well defined. */
25277ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
25287ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj
25297ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      if (ty == Ity_I32)
25307ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj         assign(rot_amt, mkexpr(rot_amt32));
25317ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      else
25327ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj         assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
2533750f407b6be1aac303964a219acf0a6de8b8c4dasewardj
2534750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      if (left) {
25351813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
2536750f407b6be1aac303964a219acf0a6de8b8c4dasewardj         /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2537750f407b6be1aac303964a219acf0a6de8b8c4dasewardj         assign(dst1,
2538750f407b6be1aac303964a219acf0a6de8b8c4dasewardj            binop( mkSizedOp(ty,Iop_Or8),
2539750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                   binop( mkSizedOp(ty,Iop_Shl8),
2540750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                          mkexpr(dst0),
2541750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                          mkexpr(rot_amt)
2542750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                   ),
2543750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                   binop( mkSizedOp(ty,Iop_Shr8),
2544750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                          mkexpr(dst0),
2545750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                          binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2546750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                   )
2547750f407b6be1aac303964a219acf0a6de8b8c4dasewardj            )
2548750f407b6be1aac303964a219acf0a6de8b8c4dasewardj         );
25492a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         ccOp += X86G_CC_OP_ROLB;
25501813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
25511813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      } else { /* right */
25521813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
25531813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
25541813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         assign(dst1,
25551813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            binop( mkSizedOp(ty,Iop_Or8),
25561813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                   binop( mkSizedOp(ty,Iop_Shr8),
25571813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                          mkexpr(dst0),
25581813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                          mkexpr(rot_amt)
25591813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                   ),
25601813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                   binop( mkSizedOp(ty,Iop_Shl8),
25611813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                          mkexpr(dst0),
25621813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                          binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2563750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                   )
2564750f407b6be1aac303964a219acf0a6de8b8c4dasewardj            )
2565750f407b6be1aac303964a219acf0a6de8b8c4dasewardj         );
25662a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         ccOp += X86G_CC_OP_RORB;
2567c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
2568750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      }
2569c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
25701813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      /* dst1 now holds the rotated value.  Build flag thunk.  We
25711813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         need the resulting value for this, and the previous flags.
25721813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         Except don't set it if the rotate count is zero. */
25731813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
25742a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      assign(oldFlags, mk_x86g_calculate_eflags_all());
25751813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
2576009230b9758291b594e60d7c0243a73d53e81854sewardj      /* rot_amt32 :: Ity_I8.  We need to convert it to I1. */
2577009230b9758291b594e60d7c0243a73d53e81854sewardj      IRTemp rot_amt32b = newTemp(Ity_I1);
2578009230b9758291b594e60d7c0243a73d53e81854sewardj      assign(rot_amt32b, binop(Iop_CmpNE8, mkexpr(rot_amt32), mkU8(0)) );
2579009230b9758291b594e60d7c0243a73d53e81854sewardj
25802a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      /* CC_DEP1 is the rotated value.  CC_NDEP is flags before. */
25811813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      stmt( IRStmt_Put( OFFB_CC_OP,
258299dd03e04a6914d90d5fee727d61d76905334becflorian                        IRExpr_ITE( mkexpr(rot_amt32b),
258399dd03e04a6914d90d5fee727d61d76905334becflorian                                    mkU32(ccOp),
258499dd03e04a6914d90d5fee727d61d76905334becflorian                                    IRExpr_Get(OFFB_CC_OP,Ity_I32) ) ));
25852a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      stmt( IRStmt_Put( OFFB_CC_DEP1,
258699dd03e04a6914d90d5fee727d61d76905334becflorian                        IRExpr_ITE( mkexpr(rot_amt32b),
258799dd03e04a6914d90d5fee727d61d76905334becflorian                                    widenUto32(mkexpr(dst1)),
258899dd03e04a6914d90d5fee727d61d76905334becflorian                                    IRExpr_Get(OFFB_CC_DEP1,Ity_I32) ) ));
25892a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      stmt( IRStmt_Put( OFFB_CC_DEP2,
259099dd03e04a6914d90d5fee727d61d76905334becflorian                        IRExpr_ITE( mkexpr(rot_amt32b),
259199dd03e04a6914d90d5fee727d61d76905334becflorian                                    mkU32(0),
259299dd03e04a6914d90d5fee727d61d76905334becflorian                                    IRExpr_Get(OFFB_CC_DEP2,Ity_I32) ) ));
25932a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      stmt( IRStmt_Put( OFFB_CC_NDEP,
259499dd03e04a6914d90d5fee727d61d76905334becflorian                        IRExpr_ITE( mkexpr(rot_amt32b),
259599dd03e04a6914d90d5fee727d61d76905334becflorian                                    mkexpr(oldFlags),
259699dd03e04a6914d90d5fee727d61d76905334becflorian                                    IRExpr_Get(OFFB_CC_NDEP,Ity_I32) ) ));
25971813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   } /* if (isRotate) */
2598e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2599e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   /* Save result, and finish up. */
2600e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   if (epartIsReg(modrm)) {
2601e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2602f48ac19a67a98af44fe452c8c2be4192ac94b62dsewardj      if (vex_traceflags & VEX_TRACE_FE) {
2603e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj         vex_printf("%s%c ",
2604e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj                    nameGrp2(gregOfRM(modrm)), nameISize(sz) );
26056d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj         if (shift_expr_txt)
26066d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj            vex_printf("%s", shift_expr_txt);
26076d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj         else
26086d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj            ppIRExpr(shift_expr);
2609e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj         vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2610e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      }
2611e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   } else {
2612940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      storeLE(mkexpr(addr), mkexpr(dst1));
2613f48ac19a67a98af44fe452c8c2be4192ac94b62dsewardj      if (vex_traceflags & VEX_TRACE_FE) {
2614940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         vex_printf("%s%c ",
2615940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                    nameGrp2(gregOfRM(modrm)), nameISize(sz) );
26166d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj         if (shift_expr_txt)
26176d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj            vex_printf("%s", shift_expr_txt);
26186d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj         else
26196d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj            ppIRExpr(shift_expr);
2620940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         vex_printf(", %s\n", dis_buf);
2621e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      }
2622940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   }
2623e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   return delta;
2624e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj}
2625e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2626e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2627490ad3820487e34854c46befcc9c755d6afc2519sewardj/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2628490ad3820487e34854c46befcc9c755d6afc2519sewardjstatic
262952d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_Grp8_Imm ( UChar sorb,
2630e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                    Bool locked,
263152d049186d07991237a825ec88aa7f1f303edb70sewardj                    Int delta, UChar modrm,
2632490ad3820487e34854c46befcc9c755d6afc2519sewardj                    Int am_sz, Int sz, UInt src_val,
2633490ad3820487e34854c46befcc9c755d6afc2519sewardj                    Bool* decode_OK )
2634490ad3820487e34854c46befcc9c755d6afc2519sewardj{
2635490ad3820487e34854c46befcc9c755d6afc2519sewardj   /* src_val denotes a d8.
2636490ad3820487e34854c46befcc9c755d6afc2519sewardj      And delta on entry points at the modrm byte. */
2637490ad3820487e34854c46befcc9c755d6afc2519sewardj
2638490ad3820487e34854c46befcc9c755d6afc2519sewardj   IRType ty     = szToITy(sz);
2639490ad3820487e34854c46befcc9c755d6afc2519sewardj   IRTemp t2     = newTemp(Ity_I32);
2640490ad3820487e34854c46befcc9c755d6afc2519sewardj   IRTemp t2m    = newTemp(Ity_I32);
2641490ad3820487e34854c46befcc9c755d6afc2519sewardj   IRTemp t_addr = IRTemp_INVALID;
2642490ad3820487e34854c46befcc9c755d6afc2519sewardj   HChar  dis_buf[50];
2643490ad3820487e34854c46befcc9c755d6afc2519sewardj   UInt   mask;
2644e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2645490ad3820487e34854c46befcc9c755d6afc2519sewardj   /* we're optimists :-) */
2646490ad3820487e34854c46befcc9c755d6afc2519sewardj   *decode_OK = True;
2647cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
2648490ad3820487e34854c46befcc9c755d6afc2519sewardj   /* Limit src_val -- the bit offset -- to something within a word.
2649490ad3820487e34854c46befcc9c755d6afc2519sewardj      The Intel docs say that literal offsets larger than a word are
2650490ad3820487e34854c46befcc9c755d6afc2519sewardj      masked in this way. */
2651490ad3820487e34854c46befcc9c755d6afc2519sewardj   switch (sz) {
2652490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 2:  src_val &= 15; break;
2653490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 4:  src_val &= 31; break;
2654490ad3820487e34854c46befcc9c755d6afc2519sewardj      default: *decode_OK = False; return delta;
2655490ad3820487e34854c46befcc9c755d6afc2519sewardj   }
2656490ad3820487e34854c46befcc9c755d6afc2519sewardj
2657490ad3820487e34854c46befcc9c755d6afc2519sewardj   /* Invent a mask suitable for the operation. */
2658490ad3820487e34854c46befcc9c755d6afc2519sewardj   switch (gregOfRM(modrm)) {
2659490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 4: /* BT */  mask = 0;               break;
2660490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 5: /* BTS */ mask = 1 << src_val;    break;
2661490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 6: /* BTR */ mask = ~(1 << src_val); break;
2662490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 7: /* BTC */ mask = 1 << src_val;    break;
2663490ad3820487e34854c46befcc9c755d6afc2519sewardj         /* If this needs to be extended, probably simplest to make a
2664490ad3820487e34854c46befcc9c755d6afc2519sewardj            new function to handle the other cases (0 .. 3).  The
2665490ad3820487e34854c46befcc9c755d6afc2519sewardj            Intel docs do however not indicate any use for 0 .. 3, so
2666490ad3820487e34854c46befcc9c755d6afc2519sewardj            we don't expect this to happen. */
2667490ad3820487e34854c46befcc9c755d6afc2519sewardj      default: *decode_OK = False; return delta;
2668490ad3820487e34854c46befcc9c755d6afc2519sewardj   }
2669490ad3820487e34854c46befcc9c755d6afc2519sewardj
2670490ad3820487e34854c46befcc9c755d6afc2519sewardj   /* Fetch the value to be tested and modified into t2, which is
2671490ad3820487e34854c46befcc9c755d6afc2519sewardj      32-bits wide regardless of sz. */
2672490ad3820487e34854c46befcc9c755d6afc2519sewardj   if (epartIsReg(modrm)) {
2673490ad3820487e34854c46befcc9c755d6afc2519sewardj      vassert(am_sz == 1);
26745a8334e7eb11f2d194f4c6ed9472027af21ab4ebsewardj      assign( t2, widenUto32(getIReg(sz, eregOfRM(modrm))) );
2675490ad3820487e34854c46befcc9c755d6afc2519sewardj      delta += (am_sz + 1);
2676490ad3820487e34854c46befcc9c755d6afc2519sewardj      DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2677490ad3820487e34854c46befcc9c755d6afc2519sewardj                              src_val, nameIReg(sz,eregOfRM(modrm)));
2678490ad3820487e34854c46befcc9c755d6afc2519sewardj   } else {
2679490ad3820487e34854c46befcc9c755d6afc2519sewardj      Int len;
2680490ad3820487e34854c46befcc9c755d6afc2519sewardj      t_addr = disAMode ( &len, sorb, delta, dis_buf);
2681490ad3820487e34854c46befcc9c755d6afc2519sewardj      delta  += (len+1);
2682490ad3820487e34854c46befcc9c755d6afc2519sewardj      assign( t2, widenUto32(loadLE(ty, mkexpr(t_addr))) );
2683490ad3820487e34854c46befcc9c755d6afc2519sewardj      DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2684490ad3820487e34854c46befcc9c755d6afc2519sewardj                              src_val, dis_buf);
2685490ad3820487e34854c46befcc9c755d6afc2519sewardj   }
2686490ad3820487e34854c46befcc9c755d6afc2519sewardj
2687490ad3820487e34854c46befcc9c755d6afc2519sewardj   /* Compute the new value into t2m, if non-BT. */
2688490ad3820487e34854c46befcc9c755d6afc2519sewardj   switch (gregOfRM(modrm)) {
2689490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 4: /* BT */
2690490ad3820487e34854c46befcc9c755d6afc2519sewardj         break;
2691490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 5: /* BTS */
2692490ad3820487e34854c46befcc9c755d6afc2519sewardj         assign( t2m, binop(Iop_Or32, mkU32(mask), mkexpr(t2)) );
2693490ad3820487e34854c46befcc9c755d6afc2519sewardj         break;
2694490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 6: /* BTR */
2695490ad3820487e34854c46befcc9c755d6afc2519sewardj         assign( t2m, binop(Iop_And32, mkU32(mask), mkexpr(t2)) );
2696490ad3820487e34854c46befcc9c755d6afc2519sewardj         break;
2697490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 7: /* BTC */
2698490ad3820487e34854c46befcc9c755d6afc2519sewardj         assign( t2m, binop(Iop_Xor32, mkU32(mask), mkexpr(t2)) );
2699490ad3820487e34854c46befcc9c755d6afc2519sewardj         break;
2700ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      default:
2701ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj         /*NOTREACHED*/ /*the previous switch guards this*/
2702490ad3820487e34854c46befcc9c755d6afc2519sewardj         vassert(0);
2703490ad3820487e34854c46befcc9c755d6afc2519sewardj   }
2704490ad3820487e34854c46befcc9c755d6afc2519sewardj
2705e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* Write the result back, if non-BT.  If the CAS fails then we
2706e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      side-exit from the trace at this point, and so the flag state is
2707e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      not affected.  This is of course as required. */
2708490ad3820487e34854c46befcc9c755d6afc2519sewardj   if (gregOfRM(modrm) != 4 /* BT */) {
2709490ad3820487e34854c46befcc9c755d6afc2519sewardj      if (epartIsReg(modrm)) {
2710e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         putIReg(sz, eregOfRM(modrm), narrowTo(ty, mkexpr(t2m)));
2711490ad3820487e34854c46befcc9c755d6afc2519sewardj      } else {
2712e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (locked) {
2713e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            casLE( mkexpr(t_addr),
2714e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                   narrowTo(ty, mkexpr(t2))/*expd*/,
2715e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                   narrowTo(ty, mkexpr(t2m))/*new*/,
2716e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                   guest_EIP_curr_instr );
2717e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         } else {
2718e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
2719e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
2720490ad3820487e34854c46befcc9c755d6afc2519sewardj      }
2721490ad3820487e34854c46befcc9c755d6afc2519sewardj   }
2722490ad3820487e34854c46befcc9c755d6afc2519sewardj
2723e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* Copy relevant bit from t2 into the carry flag. */
2724e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
2725e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
2726e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2727e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   stmt( IRStmt_Put(
2728e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            OFFB_CC_DEP1,
2729e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            binop(Iop_And32,
2730e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  binop(Iop_Shr32, mkexpr(t2), mkU8(src_val)),
2731e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  mkU32(1))
2732e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj       ));
2733e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
2734e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      elimination of previous stores to this field work better. */
2735e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
2736e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
2737490ad3820487e34854c46befcc9c755d6afc2519sewardj   return delta;
2738490ad3820487e34854c46befcc9c755d6afc2519sewardj}
2739cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
2740cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
27411813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj/* Signed/unsigned widening multiply.  Generate IR to multiply the
27421813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   value in EAX/AX/AL by the given IRTemp, and park the result in
27431813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   EDX:EAX/DX:AX/AX.
2744cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj*/
27451813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardjstatic void codegen_mulL_A_D ( Int sz, Bool syned,
274655085f8680acc89d727e321f3b34cae1a8c4093aflorian                               IRTemp tmp, const HChar* tmp_txt )
2747cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj{
2748cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   IRType ty = szToITy(sz);
2749cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   IRTemp t1 = newTemp(ty);
2750cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
27511813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   assign( t1, getIReg(sz, R_EAX) );
2752cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
2753cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   switch (ty) {
2754b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      case Ity_I32: {
2755b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         IRTemp res64   = newTemp(Ity_I64);
2756948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         IRTemp resHi   = newTemp(Ity_I32);
2757948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         IRTemp resLo   = newTemp(Ity_I32);
2758b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         IROp   mulOp   = syned ? Iop_MullS32 : Iop_MullU32;
27592a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         UInt   tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
27602a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
2761b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2762948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2763948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         assign( resLo, unop(Iop_64to32,mkexpr(res64)));
2764948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         putIReg(4, R_EDX, mkexpr(resHi));
2765948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         putIReg(4, R_EAX, mkexpr(resLo));
2766b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         break;
2767b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      }
2768b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      case Ity_I16: {
2769b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         IRTemp res32   = newTemp(Ity_I32);
2770948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         IRTemp resHi   = newTemp(Ity_I16);
2771948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         IRTemp resLo   = newTemp(Ity_I16);
2772b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         IROp   mulOp   = syned ? Iop_MullS16 : Iop_MullU16;
27732a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         UInt   tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
27742a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
2775b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2776948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2777948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         assign( resLo, unop(Iop_32to16,mkexpr(res32)));
2778948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         putIReg(2, R_EDX, mkexpr(resHi));
2779948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         putIReg(2, R_EAX, mkexpr(resLo));
2780b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         break;
2781b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      }
2782b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      case Ity_I8: {
2783b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         IRTemp res16   = newTemp(Ity_I16);
2784948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         IRTemp resHi   = newTemp(Ity_I8);
2785948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         IRTemp resLo   = newTemp(Ity_I8);
2786b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         IROp   mulOp   = syned ? Iop_MullS8 : Iop_MullU8;
27872a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         UInt   tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
27882a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
2789b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2790948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2791948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         assign( resLo, unop(Iop_16to8,mkexpr(res16)));
2792b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         putIReg(2, R_EAX, mkexpr(res16));
2793b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         break;
2794b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      }
2795b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      default:
2796b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         vpanic("codegen_mulL_A_D(x86)");
2797cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   }
27981813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
2799cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj}
2800cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
2801940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
2802940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj/* Group 3 extended opcodes. */
2803940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardjstatic
2804e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardjUInt dis_Grp3 ( UChar sorb, Bool locked, Int sz, Int delta, Bool* decode_OK )
2805940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj{
2806c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   UInt    d32;
2807c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   UChar   modrm;
2808c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar   dis_buf[50];
2809c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   Int     len;
2810c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   IRTemp  addr;
2811940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   IRType  ty = szToITy(sz);
2812940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   IRTemp  t1 = newTemp(ty);
2813940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   IRTemp dst1, src, dst0;
2814d51dc81599cba69ddc133f56c743205330f9dc40sewardj
2815d51dc81599cba69ddc133f56c743205330f9dc40sewardj   *decode_OK = True; /* may change this later */
2816d51dc81599cba69ddc133f56c743205330f9dc40sewardj
2817940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   modrm = getIByte(delta);
2818e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
2819e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   if (locked && (gregOfRM(modrm) != 2 && gregOfRM(modrm) != 3)) {
2820e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* LOCK prefix only allowed with not and neg subopcodes */
2821e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      *decode_OK = False;
2822e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      return delta;
2823e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
2824e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
2825940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   if (epartIsReg(modrm)) {
2826940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      switch (gregOfRM(modrm)) {
2827c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         case 0: { /* TEST */
2828c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            delta++; d32 = getUDisp(sz, delta); delta += sz;
28295bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            dst1 = newTemp(ty);
28305bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            assign(dst1, binop(mkSizedOp(ty,Iop_And8),
28315bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                               getIReg(sz,eregOfRM(modrm)),
2832c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj                               mkU(ty,d32)));
28335bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            setFlags_DEP1( Iop_And8, dst1, ty );
2834c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2835c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj                                      nameIReg(sz, eregOfRM(modrm)));
2836c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            break;
2837c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         }
2838d51dc81599cba69ddc133f56c743205330f9dc40sewardj         case 1: /* UNDEFINED */
2839d51dc81599cba69ddc133f56c743205330f9dc40sewardj           /* The Intel docs imply this insn is undefined and binutils
2840d51dc81599cba69ddc133f56c743205330f9dc40sewardj              agrees.  Unfortunately Core 2 will run it (with who
2841d51dc81599cba69ddc133f56c743205330f9dc40sewardj              knows what result?)  sandpile.org reckons it's an alias
2842d51dc81599cba69ddc133f56c743205330f9dc40sewardj              for case 0.  We play safe. */
2843d51dc81599cba69ddc133f56c743205330f9dc40sewardj           *decode_OK = False;
2844d51dc81599cba69ddc133f56c743205330f9dc40sewardj           break;
2845940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         case 2: /* NOT */
2846940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            delta++;
2847940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            putIReg(sz, eregOfRM(modrm),
2848940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                        unop(mkSizedOp(ty,Iop_Not8),
2849940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                             getIReg(sz, eregOfRM(modrm))));
2850940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2851940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            break;
2852940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         case 3: /* NEG */
2853940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            delta++;
2854940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            dst0 = newTemp(ty);
2855940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            src  = newTemp(ty);
2856940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            dst1 = newTemp(ty);
28575bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            assign(dst0, mkU(ty,0));
2858a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj            assign(src,  getIReg(sz,eregOfRM(modrm)));
2859eb17e49565dd7867a56c8ba6e45fdca01a576bb3sewardj            assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
28602a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
28615bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2862940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2863940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            break;
2864cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj         case 4: /* MUL (unsigned widening) */
2865cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj            delta++;
28661813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            src = newTemp(ty);
28675bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            assign(src, getIReg(sz,eregOfRM(modrm)));
28681813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
2869cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj            break;
2870caca9d0d3729c36af6ae02b0654cb289101248cbsewardj         case 5: /* IMUL (signed widening) */
2871caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            delta++;
28721813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            src = newTemp(ty);
28735bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            assign(src, getIReg(sz,eregOfRM(modrm)));
28741813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
2875caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            break;
287668511549b138ef55c8d31088cb0f20a72d83ab2bsewardj         case 6: /* DIV */
287768511549b138ef55c8d31088cb0f20a72d83ab2bsewardj            delta++;
287868511549b138ef55c8d31088cb0f20a72d83ab2bsewardj            assign( t1, getIReg(sz, eregOfRM(modrm)) );
287968511549b138ef55c8d31088cb0f20a72d83ab2bsewardj            codegen_div ( sz, t1, False );
288068511549b138ef55c8d31088cb0f20a72d83ab2bsewardj            DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
288168511549b138ef55c8d31088cb0f20a72d83ab2bsewardj            break;
2882caca9d0d3729c36af6ae02b0654cb289101248cbsewardj         case 7: /* IDIV */
2883caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            delta++;
2884caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            assign( t1, getIReg(sz, eregOfRM(modrm)) );
2885caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            codegen_div ( sz, t1, True );
2886caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2887caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            break;
2888940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         default:
2889d51dc81599cba69ddc133f56c743205330f9dc40sewardj            /* This can't happen - gregOfRM should return 0 .. 7 only */
2890940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            vpanic("Grp3(x86)");
2891940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      }
2892940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   } else {
2893c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      addr = disAMode ( &len, sorb, delta, dis_buf );
2894c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      t1   = newTemp(ty);
2895c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      delta += len;
2896c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      assign(t1, loadLE(ty,mkexpr(addr)));
2897c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      switch (gregOfRM(modrm)) {
2898c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         case 0: { /* TEST */
2899c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            d32 = getUDisp(sz, delta); delta += sz;
29005bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            dst1 = newTemp(ty);
29015bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            assign(dst1, binop(mkSizedOp(ty,Iop_And8),
29025bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                               mkexpr(t1), mkU(ty,d32)));
29035bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            setFlags_DEP1( Iop_And8, dst1, ty );
2904c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2905c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            break;
2906c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         }
2907d51dc81599cba69ddc133f56c743205330f9dc40sewardj         case 1: /* UNDEFINED */
2908d51dc81599cba69ddc133f56c743205330f9dc40sewardj           /* See comment above on R case */
2909d51dc81599cba69ddc133f56c743205330f9dc40sewardj           *decode_OK = False;
2910d51dc81599cba69ddc133f56c743205330f9dc40sewardj           break;
291178fe7910833f29826df06f3ff6f0238f0c41e6e2sewardj         case 2: /* NOT */
2912e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            dst1 = newTemp(ty);
2913e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            assign(dst1, unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2914e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
2915e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2916e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                    guest_EIP_curr_instr );
2917e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
2918e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE( mkexpr(addr), mkexpr(dst1) );
2919e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
292078fe7910833f29826df06f3ff6f0238f0c41e6e2sewardj            DIP("not%c %s\n", nameISize(sz), dis_buf);
292178fe7910833f29826df06f3ff6f0238f0c41e6e2sewardj            break;
29220c12ea83187de020a5484b4327e2427ea3451380sewardj         case 3: /* NEG */
29230c12ea83187de020a5484b4327e2427ea3451380sewardj            dst0 = newTemp(ty);
29240c12ea83187de020a5484b4327e2427ea3451380sewardj            src  = newTemp(ty);
29250c12ea83187de020a5484b4327e2427ea3451380sewardj            dst1 = newTemp(ty);
29265bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            assign(dst0, mkU(ty,0));
2927a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj            assign(src,  mkexpr(t1));
2928e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            assign(dst1, binop(mkSizedOp(ty,Iop_Sub8),
2929e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                               mkexpr(dst0), mkexpr(src)));
2930e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
2931e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2932e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                    guest_EIP_curr_instr );
2933e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
2934e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE( mkexpr(addr), mkexpr(dst1) );
2935e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
29362a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
29370c12ea83187de020a5484b4327e2427ea3451380sewardj            DIP("neg%c %s\n", nameISize(sz), dis_buf);
29380c12ea83187de020a5484b4327e2427ea3451380sewardj            break;
29391813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         case 4: /* MUL */
29401813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            codegen_mulL_A_D ( sz, False, t1, dis_buf );
29411813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            break;
29421813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         case 5: /* IMUL */
29431813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            codegen_mulL_A_D ( sz, True, t1, dis_buf );
29441813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            break;
29459690d927540d730525a5f7f14663f3ceaa7818dasewardj         case 6: /* DIV */
29469690d927540d730525a5f7f14663f3ceaa7818dasewardj            codegen_div ( sz, t1, False );
29479690d927540d730525a5f7f14663f3ceaa7818dasewardj            DIP("div%c %s\n", nameISize(sz), dis_buf);
29489690d927540d730525a5f7f14663f3ceaa7818dasewardj            break;
29491813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         case 7: /* IDIV */
29501813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            codegen_div ( sz, t1, True );
29511813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            DIP("idiv%c %s\n", nameISize(sz), dis_buf);
29521813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            break;
2953c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         default:
2954d51dc81599cba69ddc133f56c743205330f9dc40sewardj            /* This can't happen - gregOfRM should return 0 .. 7 only */
2955c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            vpanic("Grp3(x86)");
2956c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      }
2957940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   }
2958940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   return delta;
2959940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj}
2960940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
2961940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
2962c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj/* Group 4 extended opcodes. */
2963c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardjstatic
2964e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardjUInt dis_Grp4 ( UChar sorb, Bool locked, Int delta, Bool* decode_OK )
2965c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj{
2966c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   Int   alen;
2967c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   UChar modrm;
2968c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
2969c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   IRType ty = Ity_I8;
29707ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj   IRTemp t1 = newTemp(ty);
29717ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj   IRTemp t2 = newTemp(ty);
2972c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
2973d51dc81599cba69ddc133f56c743205330f9dc40sewardj   *decode_OK = True;
2974d51dc81599cba69ddc133f56c743205330f9dc40sewardj
2975c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   modrm = getIByte(delta);
2976e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
2977e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
2978e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* LOCK prefix only allowed with inc and dec subopcodes */
2979e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      *decode_OK = False;
2980e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      return delta;
2981e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
2982e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
2983c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   if (epartIsReg(modrm)) {
2984c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      assign(t1, getIReg(1, eregOfRM(modrm)));
2985c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      switch (gregOfRM(modrm)) {
29867ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj         case 0: /* INC */
29877ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
29887ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            putIReg(1, eregOfRM(modrm), mkexpr(t2));
29897ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            setFlags_INC_DEC( True, t2, ty );
29907ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            break;
2991c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         case 1: /* DEC */
2992c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2993c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            putIReg(1, eregOfRM(modrm), mkexpr(t2));
2994c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            setFlags_INC_DEC( False, t2, ty );
2995c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            break;
2996c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         default:
2997d51dc81599cba69ddc133f56c743205330f9dc40sewardj            *decode_OK = False;
2998d51dc81599cba69ddc133f56c743205330f9dc40sewardj            return delta;
2999c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      }
3000c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      delta++;
3001c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
3002c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj                      nameIReg(1, eregOfRM(modrm)));
3003c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   } else {
30047ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
30057ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      assign( t1, loadLE(ty, mkexpr(addr)) );
30067ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      switch (gregOfRM(modrm)) {
3007588ea765122c1ecb97991eea513b12504e35d55esewardj         case 0: /* INC */
3008588ea765122c1ecb97991eea513b12504e35d55esewardj            assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3009e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
3010e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3011e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                      guest_EIP_curr_instr );
3012e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
3013e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE( mkexpr(addr), mkexpr(t2) );
3014e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
3015588ea765122c1ecb97991eea513b12504e35d55esewardj            setFlags_INC_DEC( True, t2, ty );
3016588ea765122c1ecb97991eea513b12504e35d55esewardj            break;
30177ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj         case 1: /* DEC */
30187ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3019e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
3020e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3021e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                      guest_EIP_curr_instr );
3022e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
3023e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE( mkexpr(addr), mkexpr(t2) );
3024e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
30257ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            setFlags_INC_DEC( False, t2, ty );
30267ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            break;
30277ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj         default:
3028d51dc81599cba69ddc133f56c743205330f9dc40sewardj            *decode_OK = False;
3029d51dc81599cba69ddc133f56c743205330f9dc40sewardj            return delta;
30307ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      }
30317ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      delta += alen;
30327ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
3033c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   }
3034c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   return delta;
3035c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj}
30360611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
30370611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
30380611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj/* Group 5 extended opcodes. */
30390611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardjstatic
3040e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardjUInt dis_Grp5 ( UChar sorb, Bool locked, Int sz, Int delta,
3041c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                /*MOD*/DisResult* dres, /*OUT*/Bool* decode_OK )
30420611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj{
30430611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   Int     len;
30440611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   UChar   modrm;
3045c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar   dis_buf[50];
304692d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp  addr = IRTemp_INVALID;
30470611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   IRType  ty = szToITy(sz);
30480611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   IRTemp  t1 = newTemp(ty);
304992d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp  t2 = IRTemp_INVALID;
30500611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
3051d51dc81599cba69ddc133f56c743205330f9dc40sewardj   *decode_OK = True;
3052d51dc81599cba69ddc133f56c743205330f9dc40sewardj
30530611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   modrm = getIByte(delta);
3054e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
3055e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
3056e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* LOCK prefix only allowed with inc and dec subopcodes */
3057e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      *decode_OK = False;
3058e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      return delta;
3059e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
3060e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
30610611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   if (epartIsReg(modrm)) {
3062940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      assign(t1, getIReg(sz,eregOfRM(modrm)));
30630611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      switch (gregOfRM(modrm)) {
306459ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj         case 0: /* INC */
306559ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            vassert(sz == 2 || sz == 4);
306659ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            t2 = newTemp(ty);
306759ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            assign(t2, binop(mkSizedOp(ty,Iop_Add8),
306859ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj                             mkexpr(t1), mkU(ty,1)));
306959ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            setFlags_INC_DEC( True, t2, ty );
307059ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            putIReg(sz,eregOfRM(modrm),mkexpr(t2));
307159ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            break;
307259ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj         case 1: /* DEC */
307359ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            vassert(sz == 2 || sz == 4);
307459ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            t2 = newTemp(ty);
307559ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
307659ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj                             mkexpr(t1), mkU(ty,1)));
307759ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            setFlags_INC_DEC( False, t2, ty );
307859ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            putIReg(sz,eregOfRM(modrm),mkexpr(t2));
307959ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            break;
3080c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         case 2: /* call Ev */
3081c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            vassert(sz == 4);
3082c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            t2 = newTemp(Ity_I32);
3083c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3084c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            putIReg(4, R_ESP, mkexpr(t2));
30859e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+1));
3086c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_treg(dres, Ijk_Call, t1);
3087c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres->whatNext == Dis_StopHere);
3088c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            break;
30890611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         case 4: /* jmp Ev */
30900611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj            vassert(sz == 4);
3091c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_treg(dres, Ijk_Boring, t1);
3092c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres->whatNext == Dis_StopHere);
30930611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj            break;
309428905821e7c91626aa61ef496b597029b0b25e0dsewardj         case 6: /* PUSH Ev */
309528905821e7c91626aa61ef496b597029b0b25e0dsewardj            vassert(sz == 4 || sz == 2);
309628905821e7c91626aa61ef496b597029b0b25e0dsewardj            t2 = newTemp(Ity_I32);
309728905821e7c91626aa61ef496b597029b0b25e0dsewardj            assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
309828905821e7c91626aa61ef496b597029b0b25e0dsewardj            putIReg(4, R_ESP, mkexpr(t2) );
309928905821e7c91626aa61ef496b597029b0b25e0dsewardj            storeLE( mkexpr(t2), mkexpr(t1) );
310028905821e7c91626aa61ef496b597029b0b25e0dsewardj            break;
31010611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         default:
3102d51dc81599cba69ddc133f56c743205330f9dc40sewardj            *decode_OK = False;
3103d51dc81599cba69ddc133f56c743205330f9dc40sewardj            return delta;
31040611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      }
31050611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      delta++;
31060611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
31070611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                       nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
31080611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   } else {
31090611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      addr = disAMode ( &len, sorb, delta, dis_buf );
3110940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      assign(t1, loadLE(ty,mkexpr(addr)));
31110611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      switch (gregOfRM(modrm)) {
31120611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         case 0: /* INC */
31130611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj            t2 = newTemp(ty);
31140611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj            assign(t2, binop(mkSizedOp(ty,Iop_Add8),
31150611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                             mkexpr(t1), mkU(ty,1)));
3116e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
3117e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr),
3118e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                      mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3119e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
3120e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE(mkexpr(addr),mkexpr(t2));
3121e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
31220611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj            setFlags_INC_DEC( True, t2, ty );
31230611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj            break;
3124c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         case 1: /* DEC */
3125c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            t2 = newTemp(ty);
3126c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3127c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj                             mkexpr(t1), mkU(ty,1)));
3128e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
3129e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr),
3130e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                      mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3131e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
3132e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE(mkexpr(addr),mkexpr(t2));
3133e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
3134c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            setFlags_INC_DEC( False, t2, ty );
3135c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            break;
313677b86be374085943e902075b305ff047a053aac6sewardj         case 2: /* call Ev */
313777b86be374085943e902075b305ff047a053aac6sewardj            vassert(sz == 4);
313877b86be374085943e902075b305ff047a053aac6sewardj            t2 = newTemp(Ity_I32);
313977b86be374085943e902075b305ff047a053aac6sewardj            assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
314077b86be374085943e902075b305ff047a053aac6sewardj            putIReg(4, R_ESP, mkexpr(t2));
31419e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+len));
3142c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_treg(dres, Ijk_Call, t1);
3143c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres->whatNext == Dis_StopHere);
314477b86be374085943e902075b305ff047a053aac6sewardj            break;
314577b86be374085943e902075b305ff047a053aac6sewardj         case 4: /* JMP Ev */
314677b86be374085943e902075b305ff047a053aac6sewardj            vassert(sz == 4);
3147c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_treg(dres, Ijk_Boring, t1);
3148c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres->whatNext == Dis_StopHere);
314977b86be374085943e902075b305ff047a053aac6sewardj            break;
31500c12ea83187de020a5484b4327e2427ea3451380sewardj         case 6: /* PUSH Ev */
31510c12ea83187de020a5484b4327e2427ea3451380sewardj            vassert(sz == 4 || sz == 2);
31520c12ea83187de020a5484b4327e2427ea3451380sewardj            t2 = newTemp(Ity_I32);
31530c12ea83187de020a5484b4327e2427ea3451380sewardj            assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
31540c12ea83187de020a5484b4327e2427ea3451380sewardj            putIReg(4, R_ESP, mkexpr(t2) );
31555bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            storeLE( mkexpr(t2), mkexpr(t1) );
31560c12ea83187de020a5484b4327e2427ea3451380sewardj            break;
31570611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         default:
3158d51dc81599cba69ddc133f56c743205330f9dc40sewardj            *decode_OK = False;
3159d51dc81599cba69ddc133f56c743205330f9dc40sewardj            return delta;
31600611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      }
31610611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      delta += len;
31620611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
31630611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                       nameISize(sz), dis_buf);
31640611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   }
31650611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   return delta;
31660611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj}
31670611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
3168464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
316964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/*------------------------------------------------------------*/
317064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/*--- Disassembling string ops (including REP prefixes)    ---*/
317164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/*------------------------------------------------------------*/
317264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
317364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/* Code shared by all the string ops */
317464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
3175ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughesvoid dis_string_op_increment(Int sz, IRTemp t_inc)
317664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
317764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   if (sz == 4 || sz == 2) {
317864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      assign( t_inc,
317964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj              binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
31806d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj                               mkU8(sz/2) ) );
318164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   } else {
318264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      assign( t_inc,
318364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj              IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
318464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   }
318564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
318664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
318764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
318864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjvoid dis_string_op( void (*dis_OP)( Int, IRTemp ),
318955085f8680acc89d727e321f3b34cae1a8c4093aflorian                    Int sz, const HChar* name, UChar sorb )
319064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
319164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp t_inc = newTemp(Ity_I32);
31929c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj   vassert(sorb == 0); /* hmm.  so what was the point of passing it in? */
319364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   dis_string_op_increment(sz, t_inc);
319464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   dis_OP( sz, t_inc );
319564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   DIP("%s%c\n", name, nameISize(sz));
319664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
319764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
319864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
319964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjvoid dis_MOVS ( Int sz, IRTemp t_inc )
320064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
320164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRType ty = szToITy(sz);
320264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp td = newTemp(Ity_I32);   /* EDI */
320364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp ts = newTemp(Ity_I32);   /* ESI */
320464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
320564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( td, getIReg(4, R_EDI) );
320664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( ts, getIReg(4, R_ESI) );
320764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
320864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
320964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
321064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
321164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
321264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
321364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
321410ca4eb0751a48347cb6f539aff8b015a4eb94fasewardjstatic
321510ca4eb0751a48347cb6f539aff8b015a4eb94fasewardjvoid dis_LODS ( Int sz, IRTemp t_inc )
321610ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj{
321710ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   IRType ty = szToITy(sz);
321810ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   IRTemp ts = newTemp(Ity_I32);   /* ESI */
321910ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj
322010ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   assign( ts, getIReg(4, R_ESI) );
322110ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj
322210ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   putIReg( sz, R_EAX, loadLE(ty, mkexpr(ts)) );
322310ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj
322410ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
322510ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj}
322664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
322764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
322864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjvoid dis_STOS ( Int sz, IRTemp t_inc )
322964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
323064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRType ty = szToITy(sz);
323164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp ta = newTemp(ty);        /* EAX */
323264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp td = newTemp(Ity_I32);   /* EDI */
323364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
323464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( ta, getIReg(sz, R_EAX) );
323564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( td, getIReg(4, R_EDI) );
323664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
32376d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   storeLE( mkexpr(td), mkexpr(ta) );
323864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
323964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
324064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
324164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
324264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
324364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjvoid dis_CMPS ( Int sz, IRTemp t_inc )
324464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
324564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRType ty  = szToITy(sz);
32466d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp tdv = newTemp(ty);      /* (EDI) */
32476d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp tsv = newTemp(ty);      /* (ESI) */
324864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp td  = newTemp(Ity_I32); /*  EDI  */
324964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp ts  = newTemp(Ity_I32); /*  ESI  */
325064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
325164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( td, getIReg(4, R_EDI) );
325264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( ts, getIReg(4, R_ESI) );
325364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
325464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( tdv, loadLE(ty,mkexpr(td)) );
3255b9c5cf639b3b21b972599d27207a033afc76ef67sewardj   assign( tsv, loadLE(ty,mkexpr(ts)) );
325664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
32572a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
325864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
325964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
326064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
326164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
326264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
326364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
326464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjvoid dis_SCAS ( Int sz, IRTemp t_inc )
326564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
326664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRType ty  = szToITy(sz);
32678229288c4fb1331c1e638bacdd55566e1caad9edsewardj   IRTemp ta  = newTemp(ty);       /*  EAX  */
326864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp td  = newTemp(Ity_I32);  /*  EDI  */
326964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp tdv = newTemp(ty);       /* (EDI) */
327064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
3271b9c5cf639b3b21b972599d27207a033afc76ef67sewardj   assign( ta, getIReg(sz, R_EAX) );
327264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( td, getIReg(4, R_EDI) );
327364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
327464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( tdv, loadLE(ty,mkexpr(td)) );
32752a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
327664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
327764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
327864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
32798229288c4fb1331c1e638bacdd55566e1caad9edsewardj
328064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
328164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/* Wrap the appropriate string op inside a REP/REPE/REPNE.
328264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   We assume the insn is the last one in the basic block, and so emit a jump
328364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   to the next insn, rather than just falling through. */
328464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
3285c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardjvoid dis_REP_op ( /*MOD*/DisResult* dres,
3286c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                  X86Condcode cond,
328764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj                  void (*dis_OP)(Int, IRTemp),
328855085f8680acc89d727e321f3b34cae1a8c4093aflorian                  Int sz, Addr32 eip, Addr32 eip_next, const HChar* name )
328964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
329064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp t_inc = newTemp(Ity_I32);
329164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp tc    = newTemp(Ity_I32);  /*  ECX  */
329264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
329364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( tc, getIReg(4,R_ECX) );
329464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
329564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
3296893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                      Ijk_Boring,
3297c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                      IRConst_U32(eip_next), OFFB_EIP ) );
329864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
329964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
330064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
330164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   dis_string_op_increment(sz, t_inc);
330264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   dis_OP (sz, t_inc);
330364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
33042a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   if (cond == X86CondAlways) {
3305c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      jmp_lit(dres, Ijk_Boring, eip);
3306c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      vassert(dres->whatNext == Dis_StopHere);
330764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   } else {
33082a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
3309893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                         Ijk_Boring,
3310c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                         IRConst_U32(eip), OFFB_EIP ) );
3311c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      jmp_lit(dres, Ijk_Boring, eip_next);
3312c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      vassert(dres->whatNext == Dis_StopHere);
331364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   }
331464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   DIP("%s%c\n", name, nameISize(sz));
331564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
331664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
3317464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
331864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/*------------------------------------------------------------*/
331964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/*--- Arithmetic, etc.                                     ---*/
332064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/*------------------------------------------------------------*/
332164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
33222a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj/* IMUL E, G.  Supplied eip points to the modR/M byte. */
3323cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardjstatic
3324cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardjUInt dis_mul_E_G ( UChar       sorb,
3325cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj                   Int         size,
332652d049186d07991237a825ec88aa7f1f303edb70sewardj                   Int         delta0 )
3327cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj{
332871a653693124415c046b51438f748d8f7cada2f2sewardj   Int    alen;
3329c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar  dis_buf[50];
3330cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   UChar  rm = getIByte(delta0);
3331cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   IRType ty = szToITy(size);
33326d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp te = newTemp(ty);
33336d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp tg = newTemp(ty);
3334948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   IRTemp resLo = newTemp(ty);
333571a653693124415c046b51438f748d8f7cada2f2sewardj
3336948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   assign( tg, getIReg(size, gregOfRM(rm)) );
3337cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   if (epartIsReg(rm)) {
3338cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj      assign( te, getIReg(size, eregOfRM(rm)) );
3339948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   } else {
3340948d48be23eca9df7b9d33be5dca499affb7cb3asewardj      IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3341948d48be23eca9df7b9d33be5dca499affb7cb3asewardj      assign( te, loadLE(ty,mkexpr(addr)) );
3342948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   }
3343948d48be23eca9df7b9d33be5dca499affb7cb3asewardj
33442a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
3345948d48be23eca9df7b9d33be5dca499affb7cb3asewardj
33462a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
3347cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
3348948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3349948d48be23eca9df7b9d33be5dca499affb7cb3asewardj
3350948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   if (epartIsReg(rm)) {
33512a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      DIP("imul%c %s, %s\n", nameISize(size),
33522a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                             nameIReg(size,eregOfRM(rm)),
33532a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                             nameIReg(size,gregOfRM(rm)));
3354cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj      return 1+delta0;
3355cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   } else {
33562a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      DIP("imul%c %s, %s\n", nameISize(size),
33572a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                             dis_buf, nameIReg(size,gregOfRM(rm)));
335871a653693124415c046b51438f748d8f7cada2f2sewardj      return alen+delta0;
3359cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   }
3360cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj}
3361cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
3362cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
33631813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj/* IMUL I * E -> G.  Supplied eip points to the modR/M byte. */
33641813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardjstatic
33651813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardjUInt dis_imul_I_E_G ( UChar       sorb,
33661813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                      Int         size,
336752d049186d07991237a825ec88aa7f1f303edb70sewardj                      Int         delta,
33681813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                      Int         litsize )
33691813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj{
3370883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   Int    d32, alen;
3371c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar  dis_buf[50];
3372b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj   UChar  rm = getIByte(delta);
33731813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   IRType ty = szToITy(size);
33741813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   IRTemp te = newTemp(ty);
33751813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   IRTemp tl = newTemp(ty);
3376948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   IRTemp resLo = newTemp(ty);
33771813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
3378b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj   vassert(size == 1 || size == 2 || size == 4);
3379b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj
33801813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   if (epartIsReg(rm)) {
33811813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      assign(te, getIReg(size, eregOfRM(rm)));
33821813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      delta++;
33831813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   } else {
3384883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3385883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      assign(te, loadLE(ty, mkexpr(addr)));
3386883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      delta += alen;
33871813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   }
33881813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   d32 = getSDisp(litsize,delta);
33891813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   delta += litsize;
33901813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
3391b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj   if (size == 1) d32 &= 0xFF;
3392b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj   if (size == 2) d32 &= 0xFFFF;
3393b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj
33941813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   assign(tl, mkU(ty,d32));
3395948d48be23eca9df7b9d33be5dca499affb7cb3asewardj
33962a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
3397948d48be23eca9df7b9d33be5dca499affb7cb3asewardj
33982a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
3399948d48be23eca9df7b9d33be5dca499affb7cb3asewardj
3400948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   putIReg(size, gregOfRM(rm), mkexpr(resLo));
34011813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
34021813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   DIP("imul %d, %s, %s\n", d32,
34031813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj       ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
34041813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj       nameIReg(size,gregOfRM(rm)) );
34051813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   return delta;
3406948d48be23eca9df7b9d33be5dca499affb7cb3asewardj}
34071813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
34081813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
34099a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj/* Generate an IR sequence to do a count-leading-zeroes operation on
34109a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   the supplied IRTemp, and return a new IRTemp holding the result.
34119a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   'ty' may be Ity_I16 or Ity_I32 only.  In the case where the
34129a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   argument is zero, return the number of bits in the word (the
34139a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   natural semantics). */
34149a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardjstatic IRTemp gen_LZCNT ( IRType ty, IRTemp src )
34159a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj{
34169a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   vassert(ty == Ity_I32 || ty == Ity_I16);
34179a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
34189a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   IRTemp src32 = newTemp(Ity_I32);
34199a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   assign(src32, widenUto32( mkexpr(src) ));
34209a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
34219a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   IRTemp src32x = newTemp(Ity_I32);
34229a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   assign(src32x,
34239a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj          binop(Iop_Shl32, mkexpr(src32),
34249a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                           mkU8(32 - 8 * sizeofIRType(ty))));
34259a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
34269a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   // Clz32 has undefined semantics when its input is zero, so
34279a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   // special-case around that.
34289a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   IRTemp res32 = newTemp(Ity_I32);
34299a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   assign(res32,
343099dd03e04a6914d90d5fee727d61d76905334becflorian          IRExpr_ITE(
3431009230b9758291b594e60d7c0243a73d53e81854sewardj             binop(Iop_CmpEQ32, mkexpr(src32x), mkU32(0)),
343299dd03e04a6914d90d5fee727d61d76905334becflorian             mkU32(8 * sizeofIRType(ty)),
343399dd03e04a6914d90d5fee727d61d76905334becflorian             unop(Iop_Clz32, mkexpr(src32x))
34349a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   ));
34359a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
34369a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   IRTemp res = newTemp(ty);
34379a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   assign(res, narrowTo(ty, mkexpr(res32)));
34389a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   return res;
34399a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj}
34409a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
34419a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
3442d1725d18b61bf7912a9099686179faef5815dba1sewardj/*------------------------------------------------------------*/
3443464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*---                                                      ---*/
3444464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*--- x87 FLOATING POINT INSTRUCTIONS                      ---*/
3445464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*---                                                      ---*/
3446d1725d18b61bf7912a9099686179faef5815dba1sewardj/*------------------------------------------------------------*/
3447d1725d18b61bf7912a9099686179faef5815dba1sewardj
3448207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* --- Helper functions for dealing with the register stack. --- */
3449207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3450893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj/* --- Set the emulation-warning pseudo-register. --- */
3451893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj
3452893aadad7f29f7801ce26cb7575c16e90bd3767fsewardjstatic void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3453893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj{
3454dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
34556ef84bed9bb3af22060eb1759788034602bbcc88florian   stmt( IRStmt_Put( OFFB_EMNOTE, e ) );
3456893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj}
3457893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj
345817442fe8094d0f82266e5a05509f62cac8f7539esewardj/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
3459207557ab2ea38239b670785c976b89d50bbb0eccsewardj
346017442fe8094d0f82266e5a05509f62cac8f7539esewardjstatic IRExpr* mkQNaN64 ( void )
3461207557ab2ea38239b670785c976b89d50bbb0eccsewardj{
346217442fe8094d0f82266e5a05509f62cac8f7539esewardj  /* QNaN is 0 2047 1 0(51times)
346317442fe8094d0f82266e5a05509f62cac8f7539esewardj     == 0b 11111111111b 1 0(51times)
346417442fe8094d0f82266e5a05509f62cac8f7539esewardj     == 0x7FF8 0000 0000 0000
346517442fe8094d0f82266e5a05509f62cac8f7539esewardj   */
346617442fe8094d0f82266e5a05509f62cac8f7539esewardj   return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
3467207557ab2ea38239b670785c976b89d50bbb0eccsewardj}
3468207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3469893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj/* --------- Get/put the top-of-stack pointer. --------- */
3470d1725d18b61bf7912a9099686179faef5815dba1sewardj
3471d1725d18b61bf7912a9099686179faef5815dba1sewardjstatic IRExpr* get_ftop ( void )
3472d1725d18b61bf7912a9099686179faef5815dba1sewardj{
3473d1725d18b61bf7912a9099686179faef5815dba1sewardj   return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3474d1725d18b61bf7912a9099686179faef5815dba1sewardj}
3475d1725d18b61bf7912a9099686179faef5815dba1sewardj
3476207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic void put_ftop ( IRExpr* e )
3477207557ab2ea38239b670785c976b89d50bbb0eccsewardj{
3478dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
3479207557ab2ea38239b670785c976b89d50bbb0eccsewardj   stmt( IRStmt_Put( OFFB_FTOP, e ) );
3480207557ab2ea38239b670785c976b89d50bbb0eccsewardj}
3481207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3482893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj/* --------- Get/put the C3210 bits. --------- */
3483bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
3484c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardjstatic IRExpr* get_C3210 ( void )
3485bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj{
3486c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj   return IRExpr_Get( OFFB_FC3210, Ity_I32 );
3487bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj}
3488bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
3489c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardjstatic void put_C3210 ( IRExpr* e )
3490bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj{
3491c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj   stmt( IRStmt_Put( OFFB_FC3210, e ) );
3492bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj}
3493207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3494893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj/* --------- Get/put the FPU rounding mode. --------- */
3495d01a9639811cd74b608f3d8877af4ad74d5089a7sewardjstatic IRExpr* /* :: Ity_I32 */ get_fpround ( void )
34968f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj{
3497d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj   return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
34988f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj}
34998f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj
3500d01a9639811cd74b608f3d8877af4ad74d5089a7sewardjstatic void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
35018f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj{
3502d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj   stmt( IRStmt_Put( OFFB_FPROUND, e ) );
35038f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj}
35048f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj
35058f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj
3506893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
35078f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj/* Produces a value in 0 .. 3, which is encoded as per the type
3508d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj   IRRoundingMode.  Since the guest_FPROUND value is also encoded as
3509d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj   per IRRoundingMode, we merely need to get it and mask it for
3510d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj   safety.
35118f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj*/
35128f3debf52b76a050bc84997a0358c4aa86dfc88dsewardjstatic IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
35138f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj{
3514d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj   return binop( Iop_And32, get_fpround(), mkU32(3) );
35158f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj}
35168f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj
3517f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardjstatic IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
3518f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj{
3519f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj   return mkU32(Irrm_NEAREST);
3520f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj}
3521f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj
35228f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj
3523207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* --------- Get/set FP register tag bytes. --------- */
3524207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3525207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3526207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3527207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic void put_ST_TAG ( Int i, IRExpr* value )
3528207557ab2ea38239b670785c976b89d50bbb0eccsewardj{
3529dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRRegArray* descr;
3530dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_I8);
3531dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
3532d6f38b3f822f7d57adfc0da3410995d85d6a4597florian   stmt( IRStmt_PutI( mkIRPutI(descr, get_ftop(), i, value) ) );
3533207557ab2ea38239b670785c976b89d50bbb0eccsewardj}
3534207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3535207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Given i, generate an expression yielding 'ST_TAG(i)'.  This will be
3536db199620ca3945e9f43d4738c159ce1860142a55sewardj   zero to indicate "Empty" and nonzero to indicate "NonEmpty".  */
3537207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3538207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic IRExpr* get_ST_TAG ( Int i )
3539d1725d18b61bf7912a9099686179faef5815dba1sewardj{
3540dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
35412d3f77c12d2911173fd182d0b6e954196dee9135sewardj   return IRExpr_GetI( descr, get_ftop(), i );
3542d1725d18b61bf7912a9099686179faef5815dba1sewardj}
3543d1725d18b61bf7912a9099686179faef5815dba1sewardj
3544207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3545207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* --------- Get/set FP registers. --------- */
3546207557ab2ea38239b670785c976b89d50bbb0eccsewardj
35472d3f77c12d2911173fd182d0b6e954196dee9135sewardj/* Given i, and some expression e, emit 'ST(i) = e' and set the
35482d3f77c12d2911173fd182d0b6e954196dee9135sewardj   register's tag to indicate the register is full.  The previous
35492d3f77c12d2911173fd182d0b6e954196dee9135sewardj   state of the register is not checked. */
3550207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3551207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic void put_ST_UNCHECKED ( Int i, IRExpr* value )
3552d1725d18b61bf7912a9099686179faef5815dba1sewardj{
3553dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRRegArray* descr;
3554dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_F64);
3555dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
3556d6f38b3f822f7d57adfc0da3410995d85d6a4597florian   stmt( IRStmt_PutI( mkIRPutI(descr, get_ftop(), i, value) ) );
3557207557ab2ea38239b670785c976b89d50bbb0eccsewardj   /* Mark the register as in-use. */
3558207557ab2ea38239b670785c976b89d50bbb0eccsewardj   put_ST_TAG(i, mkU8(1));
3559d1725d18b61bf7912a9099686179faef5815dba1sewardj}
3560d1725d18b61bf7912a9099686179faef5815dba1sewardj
3561207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Given i, and some expression e, emit
3562207557ab2ea38239b670785c976b89d50bbb0eccsewardj      ST(i) = is_full(i) ? NaN : e
3563207557ab2ea38239b670785c976b89d50bbb0eccsewardj   and set the tag accordingly.
3564207557ab2ea38239b670785c976b89d50bbb0eccsewardj*/
3565207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3566207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic void put_ST ( Int i, IRExpr* value )
3567207557ab2ea38239b670785c976b89d50bbb0eccsewardj{
3568009230b9758291b594e60d7c0243a73d53e81854sewardj   put_ST_UNCHECKED(
3569009230b9758291b594e60d7c0243a73d53e81854sewardj      i,
357099dd03e04a6914d90d5fee727d61d76905334becflorian      IRExpr_ITE( binop(Iop_CmpNE8, get_ST_TAG(i), mkU8(0)),
357199dd03e04a6914d90d5fee727d61d76905334becflorian                  /* non-0 means full */
357299dd03e04a6914d90d5fee727d61d76905334becflorian                  mkQNaN64(),
357399dd03e04a6914d90d5fee727d61d76905334becflorian                  /* 0 means empty */
357499dd03e04a6914d90d5fee727d61d76905334becflorian                  value
3575009230b9758291b594e60d7c0243a73d53e81854sewardj      )
3576207557ab2ea38239b670785c976b89d50bbb0eccsewardj   );
3577207557ab2ea38239b670785c976b89d50bbb0eccsewardj}
3578207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3579207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3580d1725d18b61bf7912a9099686179faef5815dba1sewardj/* Given i, generate an expression yielding 'ST(i)'. */
3581d1725d18b61bf7912a9099686179faef5815dba1sewardj
3582207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic IRExpr* get_ST_UNCHECKED ( Int i )
3583d1725d18b61bf7912a9099686179faef5815dba1sewardj{
3584dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRRegArray* descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
35852d3f77c12d2911173fd182d0b6e954196dee9135sewardj   return IRExpr_GetI( descr, get_ftop(), i );
3586d1725d18b61bf7912a9099686179faef5815dba1sewardj}
3587d1725d18b61bf7912a9099686179faef5815dba1sewardj
3588c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj
3589207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Given i, generate an expression yielding
3590207557ab2ea38239b670785c976b89d50bbb0eccsewardj  is_full(i) ? ST(i) : NaN
3591207557ab2ea38239b670785c976b89d50bbb0eccsewardj*/
3592d1725d18b61bf7912a9099686179faef5815dba1sewardj
3593207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic IRExpr* get_ST ( Int i )
3594d1725d18b61bf7912a9099686179faef5815dba1sewardj{
3595d1725d18b61bf7912a9099686179faef5815dba1sewardj   return
359699dd03e04a6914d90d5fee727d61d76905334becflorian      IRExpr_ITE( binop(Iop_CmpNE8, get_ST_TAG(i), mkU8(0)),
359799dd03e04a6914d90d5fee727d61d76905334becflorian                  /* non-0 means full */
359899dd03e04a6914d90d5fee727d61d76905334becflorian                  get_ST_UNCHECKED(i),
359999dd03e04a6914d90d5fee727d61d76905334becflorian                  /* 0 means empty */
360099dd03e04a6914d90d5fee727d61d76905334becflorian                  mkQNaN64());
3601d1725d18b61bf7912a9099686179faef5815dba1sewardj}
3602d1725d18b61bf7912a9099686179faef5815dba1sewardj
3603a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
3604e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj/* Given i, and some expression e, and a condition cond, generate IR
3605e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   which has the same effect as put_ST(i,e) when cond is true and has
3606e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   no effect when cond is false.  Given the lack of proper
3607e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   if-then-else in the IR, this is pretty tricky.
3608e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj*/
3609e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3610e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardjstatic void maybe_put_ST ( IRTemp cond, Int i, IRExpr* value )
3611e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj{
3612e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   // new_tag = if cond then FULL else old_tag
3613e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   // new_val = if cond then (if old_tag==FULL then NaN else val)
3614e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   //                   else old_val
3615e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3616e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp old_tag = newTemp(Ity_I8);
3617e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(old_tag, get_ST_TAG(i));
3618e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp new_tag = newTemp(Ity_I8);
3619e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(new_tag,
3620e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj          IRExpr_ITE(mkexpr(cond), mkU8(1)/*FULL*/, mkexpr(old_tag)));
3621e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3622e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp old_val = newTemp(Ity_F64);
3623e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(old_val, get_ST_UNCHECKED(i));
3624e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp new_val = newTemp(Ity_F64);
3625e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(new_val,
3626e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj          IRExpr_ITE(mkexpr(cond),
3627e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     IRExpr_ITE(binop(Iop_CmpNE8, mkexpr(old_tag), mkU8(0)),
3628e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                                /* non-0 means full */
3629e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                                mkQNaN64(),
3630e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                                /* 0 means empty */
3631e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                                value),
3632e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(old_val)));
3633e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3634e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   put_ST_UNCHECKED(i, mkexpr(new_val));
3635e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   // put_ST_UNCHECKED incorrectly sets tag(i) to always be FULL.  So
3636e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   // now set it to new_tag instead.
3637e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   put_ST_TAG(i, mkexpr(new_tag));
3638e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj}
3639e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3640207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Adjust FTOP downwards by one register. */
3641207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3642207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic void fp_push ( void )
3643a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj{
36442d3f77c12d2911173fd182d0b6e954196dee9135sewardj   put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
3645a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj}
3646a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
3647e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj/* Adjust FTOP downwards by one register when COND is 1:I1.  Else
3648e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   don't change it. */
3649e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3650e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardjstatic void maybe_fp_push ( IRTemp cond )
3651e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj{
3652e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   put_ftop( binop(Iop_Sub32, get_ftop(), unop(Iop_1Uto32,mkexpr(cond))) );
3653e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj}
3654e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3655207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Adjust FTOP upwards by one register, and mark the vacated register
3656207557ab2ea38239b670785c976b89d50bbb0eccsewardj   as empty.  */
3657207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3658207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic void fp_pop ( void )
3659207557ab2ea38239b670785c976b89d50bbb0eccsewardj{
3660db199620ca3945e9f43d4738c159ce1860142a55sewardj   put_ST_TAG(0, mkU8(0));
36612d3f77c12d2911173fd182d0b6e954196dee9135sewardj   put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
3662207557ab2ea38239b670785c976b89d50bbb0eccsewardj}
3663207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3664e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj/* Set the C2 bit of the FPU status register to e[0].  Assumes that
3665e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   e[31:1] == 0.
3666e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj*/
3667e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardjstatic void set_C2 ( IRExpr* e )
3668e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj{
3669e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRExpr* cleared = binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2));
3670e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   put_C3210( binop(Iop_Or32,
3671e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                    cleared,
3672e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                    binop(Iop_Shl32, e, mkU8(X86G_FC_SHIFT_C2))) );
3673e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj}
3674e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3675e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj/* Generate code to check that abs(d64) < 2^63 and is finite.  This is
3676e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   used to do the range checks for FSIN, FCOS, FSINCOS and FPTAN.  The
3677e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   test is simple, but the derivation of it is not so simple.
3678e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3679e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   The exponent field for an IEEE754 double is 11 bits.  That means it
3680e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   can take values 0 through 0x7FF.  If the exponent has value 0x7FF,
3681e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   the number is either a NaN or an Infinity and so is not finite.
3682e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   Furthermore, a finite value of exactly 2^63 is the smallest value
3683e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   that has exponent value 0x43E.  Hence, what we need to do is
3684e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   extract the exponent, ignoring the sign bit and mantissa, and check
3685e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   it is < 0x43E, or <= 0x43D.
3686e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3687e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   To make this easily applicable to 32- and 64-bit targets, a
3688e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   roundabout approach is used.  First the number is converted to I64,
3689e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   then the top 32 bits are taken.  Shifting them right by 20 bits
3690e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   places the sign bit and exponent in the bottom 12 bits.  Anding
3691e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   with 0x7FF gets rid of the sign bit, leaving just the exponent
3692e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   available for comparison.
3693e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj*/
3694e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardjstatic IRTemp math_IS_TRIG_ARG_FINITE_AND_IN_RANGE ( IRTemp d64 )
36953f61ddbfeb5ec1633b4ede7e4a057a7e77d9c9a4sewardj{
3696e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp i64 = newTemp(Ity_I64);
3697e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(i64, unop(Iop_ReinterpF64asI64, mkexpr(d64)) );
3698e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp exponent = newTemp(Ity_I32);
3699e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(exponent,
3700e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj          binop(Iop_And32,
3701e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                binop(Iop_Shr32, unop(Iop_64HIto32, mkexpr(i64)), mkU8(20)),
3702e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                mkU32(0x7FF)));
3703e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp in_range_and_finite = newTemp(Ity_I1);
3704e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(in_range_and_finite,
3705e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj          binop(Iop_CmpLE32U, mkexpr(exponent), mkU32(0x43D)));
3706e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   return in_range_and_finite;
37073f61ddbfeb5ec1633b4ede7e4a057a7e77d9c9a4sewardj}
37083f61ddbfeb5ec1633b4ede7e4a057a7e77d9c9a4sewardj
3709d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj/* Invent a plausible-looking FPU status word value:
3710d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj      ((ftop & 7) << 11) | (c3210 & 0x4700)
3711d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj */
3712d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardjstatic IRExpr* get_FPU_sw ( void )
3713d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj{
3714d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj   return
3715d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj      unop(Iop_32to16,
3716d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj           binop(Iop_Or32,
3717d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj                 binop(Iop_Shl32,
3718d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj                       binop(Iop_And32, get_ftop(), mkU32(7)),
3719d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj                             mkU8(11)),
3720d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj                       binop(Iop_And32, get_C3210(), mkU32(0x4700))
3721d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj      ));
3722d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj}
3723d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj
37243f61ddbfeb5ec1633b4ede7e4a057a7e77d9c9a4sewardj
3725207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* ------------------------------------------------------- */
3726207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Given all that stack-mangling junk, we can now go ahead
3727207557ab2ea38239b670785c976b89d50bbb0eccsewardj   and describe FP instructions.
3728207557ab2ea38239b670785c976b89d50bbb0eccsewardj*/
3729207557ab2ea38239b670785c976b89d50bbb0eccsewardj
37303fd5e570294226c643f974b438225e3f09a82f4fsewardj/* ST(0) = ST(0) `op` mem64/32(addr)
3731207557ab2ea38239b670785c976b89d50bbb0eccsewardj   Need to check ST(0)'s tag on read, but not on write.
3732207557ab2ea38239b670785c976b89d50bbb0eccsewardj*/
3733a58ea668d4725b87a146cf43cc48b8ea6ead84casewardjstatic
373455085f8680acc89d727e321f3b34cae1a8c4093aflorianvoid fp_do_op_mem_ST_0 ( IRTemp addr, const HChar* op_txt, HChar* dis_buf,
3735a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj                         IROp op, Bool dbl )
3736a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj{
373733dd31b1bcc175495b96222fa278062fd6116899sewardj   DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
3738a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj   if (dbl) {
37393fd5e570294226c643f974b438225e3f09a82f4fsewardj      put_ST_UNCHECKED(0,
3740f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj         triop( op,
3741f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
37423fd5e570294226c643f974b438225e3f09a82f4fsewardj                get_ST(0),
37433fd5e570294226c643f974b438225e3f09a82f4fsewardj                loadLE(Ity_F64,mkexpr(addr))
37443fd5e570294226c643f974b438225e3f09a82f4fsewardj         ));
3745a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj   } else {
37463fd5e570294226c643f974b438225e3f09a82f4fsewardj      put_ST_UNCHECKED(0,
3747f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj         triop( op,
3748f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
37493fd5e570294226c643f974b438225e3f09a82f4fsewardj                get_ST(0),
37503fd5e570294226c643f974b438225e3f09a82f4fsewardj                unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
37513fd5e570294226c643f974b438225e3f09a82f4fsewardj         ));
37523fd5e570294226c643f974b438225e3f09a82f4fsewardj   }
37533fd5e570294226c643f974b438225e3f09a82f4fsewardj}
37543fd5e570294226c643f974b438225e3f09a82f4fsewardj
37553fd5e570294226c643f974b438225e3f09a82f4fsewardj
37563fd5e570294226c643f974b438225e3f09a82f4fsewardj/* ST(0) = mem64/32(addr) `op` ST(0)
37573fd5e570294226c643f974b438225e3f09a82f4fsewardj   Need to check ST(0)'s tag on read, but not on write.
37583fd5e570294226c643f974b438225e3f09a82f4fsewardj*/
37593fd5e570294226c643f974b438225e3f09a82f4fsewardjstatic
376055085f8680acc89d727e321f3b34cae1a8c4093aflorianvoid fp_do_oprev_mem_ST_0 ( IRTemp addr, const HChar* op_txt, HChar* dis_buf,
3761883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                            IROp op, Bool dbl )
37623fd5e570294226c643f974b438225e3f09a82f4fsewardj{
376333dd31b1bcc175495b96222fa278062fd6116899sewardj   DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
37643fd5e570294226c643f974b438225e3f09a82f4fsewardj   if (dbl) {
37653fd5e570294226c643f974b438225e3f09a82f4fsewardj      put_ST_UNCHECKED(0,
3766f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj         triop( op,
3767f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
37683fd5e570294226c643f974b438225e3f09a82f4fsewardj                loadLE(Ity_F64,mkexpr(addr)),
37693fd5e570294226c643f974b438225e3f09a82f4fsewardj                get_ST(0)
37703fd5e570294226c643f974b438225e3f09a82f4fsewardj         ));
37713fd5e570294226c643f974b438225e3f09a82f4fsewardj   } else {
37723fd5e570294226c643f974b438225e3f09a82f4fsewardj      put_ST_UNCHECKED(0,
3773f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj         triop( op,
3774f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
37753fd5e570294226c643f974b438225e3f09a82f4fsewardj                unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
37763fd5e570294226c643f974b438225e3f09a82f4fsewardj                get_ST(0)
37773fd5e570294226c643f974b438225e3f09a82f4fsewardj         ));
3778a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj   }
3779a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj}
3780a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
3781d1725d18b61bf7912a9099686179faef5815dba1sewardj
3782db199620ca3945e9f43d4738c159ce1860142a55sewardj/* ST(dst) = ST(dst) `op` ST(src).
3783db199620ca3945e9f43d4738c159ce1860142a55sewardj   Check dst and src tags when reading but not on write.
3784db199620ca3945e9f43d4738c159ce1860142a55sewardj*/
3785db199620ca3945e9f43d4738c159ce1860142a55sewardjstatic
378655085f8680acc89d727e321f3b34cae1a8c4093aflorianvoid fp_do_op_ST_ST ( const HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
3787bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj                      Bool pop_after )
3788db199620ca3945e9f43d4738c159ce1860142a55sewardj{
3789b173774421d015736c2316b5e6e998e7de545a5cflorian   DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"",
3790b173774421d015736c2316b5e6e998e7de545a5cflorian                                 st_src, st_dst);
3791db199620ca3945e9f43d4738c159ce1860142a55sewardj   put_ST_UNCHECKED(
3792db199620ca3945e9f43d4738c159ce1860142a55sewardj      st_dst,
3793f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj      triop( op,
3794f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj             get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3795f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj             get_ST(st_dst),
3796f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj             get_ST(st_src) )
3797db199620ca3945e9f43d4738c159ce1860142a55sewardj   );
3798bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   if (pop_after)
3799bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      fp_pop();
3800bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj}
3801bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
3802bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj/* ST(dst) = ST(src) `op` ST(dst).
3803bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   Check dst and src tags when reading but not on write.
3804bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj*/
3805bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardjstatic
380655085f8680acc89d727e321f3b34cae1a8c4093aflorianvoid fp_do_oprev_ST_ST ( const HChar* op_txt, IROp op, UInt st_src,
380755085f8680acc89d727e321f3b34cae1a8c4093aflorian                         UInt st_dst, Bool pop_after )
3808bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj{
3809b173774421d015736c2316b5e6e998e7de545a5cflorian   DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"",
3810b173774421d015736c2316b5e6e998e7de545a5cflorian                                 st_src, st_dst);
3811bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   put_ST_UNCHECKED(
3812bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      st_dst,
3813f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj      triop( op,
3814f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj             get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3815f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj             get_ST(st_src),
3816f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj             get_ST(st_dst) )
3817bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   );
3818bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   if (pop_after)
3819bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      fp_pop();
3820db199620ca3945e9f43d4738c159ce1860142a55sewardj}
3821db199620ca3945e9f43d4738c159ce1860142a55sewardj
38228308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
38238308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardjstatic void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
38248308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj{
3825b173774421d015736c2316b5e6e998e7de545a5cflorian   DIP("fucomi%s %%st(0),%%st(%u)\n", pop_after ? "p" : "", i);
38268308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj   /* This is a bit of a hack (and isn't really right).  It sets
38278308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj      Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
38288308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj      documentation implies A and S are unchanged.
38298308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj   */
3830feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj   /* It's also fishy in that it is used both for COMIP and
3831feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj      UCOMIP, and they aren't the same (although similar). */
38322a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
38332a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
38342a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP1,
38358308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj                     binop( Iop_And32,
38368308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj                            binop(Iop_CmpF64, get_ST(0), get_ST(i)),
38378308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj                            mkU32(0x45)
38388308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj       )));
3839a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
3840a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      elimination of previous stores to this field work better. */
3841a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
38428308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj   if (pop_after)
38438308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj      fp_pop();
38448308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj}
38458308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
3846db199620ca3945e9f43d4738c159ce1860142a55sewardj
3847d1725d18b61bf7912a9099686179faef5815dba1sewardjstatic
384852d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
3849d1725d18b61bf7912a9099686179faef5815dba1sewardj{
3850a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj   Int    len;
3851a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj   UInt   r_src, r_dst;
3852c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar  dis_buf[50];
385389cd09353a584000edaaa61558b27253bdea7452sewardj   IRTemp t1, t2;
3854d1725d18b61bf7912a9099686179faef5815dba1sewardj
3855d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* On entry, delta points at the second byte of the insn (the modrm
3856d1725d18b61bf7912a9099686179faef5815dba1sewardj      byte).*/
3857d1725d18b61bf7912a9099686179faef5815dba1sewardj   UChar first_opcode = getIByte(delta-1);
3858d1725d18b61bf7912a9099686179faef5815dba1sewardj   UChar modrm        = getIByte(delta+0);
3859d1725d18b61bf7912a9099686179faef5815dba1sewardj
3860d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3861d1725d18b61bf7912a9099686179faef5815dba1sewardj
3862d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xD8) {
3863db199620ca3945e9f43d4738c159ce1860142a55sewardj      if (modrm < 0xC0) {
386489cd09353a584000edaaa61558b27253bdea7452sewardj
386589cd09353a584000edaaa61558b27253bdea7452sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
386689cd09353a584000edaaa61558b27253bdea7452sewardj           specifies an address. */
386789cd09353a584000edaaa61558b27253bdea7452sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
386889cd09353a584000edaaa61558b27253bdea7452sewardj         delta += len;
386989cd09353a584000edaaa61558b27253bdea7452sewardj
387089cd09353a584000edaaa61558b27253bdea7452sewardj         switch (gregOfRM(modrm)) {
387189cd09353a584000edaaa61558b27253bdea7452sewardj
38723fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0: /* FADD single-real */
38733fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
38743fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
38753fd5e570294226c643f974b438225e3f09a82f4fsewardj
387689cd09353a584000edaaa61558b27253bdea7452sewardj            case 1: /* FMUL single-real */
387789cd09353a584000edaaa61558b27253bdea7452sewardj               fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
387889cd09353a584000edaaa61558b27253bdea7452sewardj               break;
387989cd09353a584000edaaa61558b27253bdea7452sewardj
38807ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj            case 2: /* FCOM single-real */
38817ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj               DIP("fcoms %s\n", dis_buf);
38827ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj               /* This forces C1 to zero, which isn't right. */
38837ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj               put_C3210(
38847ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                   binop( Iop_And32,
38857ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                          binop(Iop_Shl32,
38867ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                                binop(Iop_CmpF64,
38877ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                                      get_ST(0),
38887ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                                      unop(Iop_F32toF64,
38897ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                                           loadLE(Ity_F32,mkexpr(addr)))),
38907ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                                mkU8(8)),
38917ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                          mkU32(0x4500)
38927ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                   ));
38937ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj               break;
38947ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj
38957ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj            case 3: /* FCOMP single-real */
3896e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               DIP("fcomps %s\n", dis_buf);
3897e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               /* This forces C1 to zero, which isn't right. */
3898e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               put_C3210(
3899e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   binop( Iop_And32,
3900e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          binop(Iop_Shl32,
3901e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                binop(Iop_CmpF64,
3902e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                      get_ST(0),
3903e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                      unop(Iop_F32toF64,
3904e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                           loadLE(Ity_F32,mkexpr(addr)))),
3905e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                mkU8(8)),
3906e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          mkU32(0x4500)
3907e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   ));
3908e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               fp_pop();
3909e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               break;
3910e166ed089645c00ea80f732139c22ec2e2c402f1sewardj
3911588ea765122c1ecb97991eea513b12504e35d55esewardj            case 4: /* FSUB single-real */
3912588ea765122c1ecb97991eea513b12504e35d55esewardj               fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3913588ea765122c1ecb97991eea513b12504e35d55esewardj               break;
3914588ea765122c1ecb97991eea513b12504e35d55esewardj
3915588ea765122c1ecb97991eea513b12504e35d55esewardj            case 5: /* FSUBR single-real */
3916588ea765122c1ecb97991eea513b12504e35d55esewardj               fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3917588ea765122c1ecb97991eea513b12504e35d55esewardj               break;
3918588ea765122c1ecb97991eea513b12504e35d55esewardj
3919bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 6: /* FDIV single-real */
3920bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3921bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
3922bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
39238308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            case 7: /* FDIVR single-real */
39248308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
39258308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               break;
39268308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
392789cd09353a584000edaaa61558b27253bdea7452sewardj            default:
3928b173774421d015736c2316b5e6e998e7de545a5cflorian               vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
392989cd09353a584000edaaa61558b27253bdea7452sewardj               vex_printf("first_opcode == 0xD8\n");
393089cd09353a584000edaaa61558b27253bdea7452sewardj               goto decode_fail;
393189cd09353a584000edaaa61558b27253bdea7452sewardj         }
3932db199620ca3945e9f43d4738c159ce1860142a55sewardj      } else {
3933db199620ca3945e9f43d4738c159ce1860142a55sewardj         delta++;
3934db199620ca3945e9f43d4738c159ce1860142a55sewardj         switch (modrm) {
393589cd09353a584000edaaa61558b27253bdea7452sewardj
3936db199620ca3945e9f43d4738c159ce1860142a55sewardj            case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
3937bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
3938db199620ca3945e9f43d4738c159ce1860142a55sewardj               break;
393989cd09353a584000edaaa61558b27253bdea7452sewardj
39403fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
39413fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
39423fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
39433fd5e570294226c643f974b438225e3f09a82f4fsewardj
3944e166ed089645c00ea80f732139c22ec2e2c402f1sewardj            /* Dunno if this is right */
3945e166ed089645c00ea80f732139c22ec2e2c402f1sewardj            case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3946e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               r_dst = (UInt)modrm - 0xD0;
3947b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fcom %%st(0),%%st(%u)\n", r_dst);
3948e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               /* This forces C1 to zero, which isn't right. */
3949e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               put_C3210(
3950e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   binop( Iop_And32,
3951e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          binop(Iop_Shl32,
3952e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3953e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                mkU8(8)),
3954e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          mkU32(0x4500)
3955e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   ));
3956e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               break;
39572d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj
395898169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj            /* Dunno if this is right */
395998169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj            case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
396098169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj               r_dst = (UInt)modrm - 0xD8;
3961b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fcomp %%st(0),%%st(%u)\n", r_dst);
396298169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj               /* This forces C1 to zero, which isn't right. */
396398169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj               put_C3210(
396498169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj                   binop( Iop_And32,
396598169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj                          binop(Iop_Shl32,
396698169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
396798169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj                                mkU8(8)),
396898169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj                          mkU32(0x4500)
396998169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj                   ));
397098169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj               fp_pop();
397198169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj               break;
39722d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj
397389cd09353a584000edaaa61558b27253bdea7452sewardj            case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
3974bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
397589cd09353a584000edaaa61558b27253bdea7452sewardj               break;
397689cd09353a584000edaaa61558b27253bdea7452sewardj
39778308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
39788308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
39798308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               break;
39808308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
39813fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
39823fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
39833fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
39843fd5e570294226c643f974b438225e3f09a82f4fsewardj
39853fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
39863fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
39873fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
39883fd5e570294226c643f974b438225e3f09a82f4fsewardj
3989db199620ca3945e9f43d4738c159ce1860142a55sewardj            default:
3990db199620ca3945e9f43d4738c159ce1860142a55sewardj               goto decode_fail;
3991db199620ca3945e9f43d4738c159ce1860142a55sewardj         }
3992db199620ca3945e9f43d4738c159ce1860142a55sewardj      }
3993d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
3994d1725d18b61bf7912a9099686179faef5815dba1sewardj
3995d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3996d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
3997d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xD9) {
3998bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj      if (modrm < 0xC0) {
399989cd09353a584000edaaa61558b27253bdea7452sewardj
400089cd09353a584000edaaa61558b27253bdea7452sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
4001feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            specifies an address. */
400289cd09353a584000edaaa61558b27253bdea7452sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
400389cd09353a584000edaaa61558b27253bdea7452sewardj         delta += len;
400489cd09353a584000edaaa61558b27253bdea7452sewardj
400589cd09353a584000edaaa61558b27253bdea7452sewardj         switch (gregOfRM(modrm)) {
400689cd09353a584000edaaa61558b27253bdea7452sewardj
400789cd09353a584000edaaa61558b27253bdea7452sewardj            case 0: /* FLD single-real */
400833dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("flds %s\n", dis_buf);
400989cd09353a584000edaaa61558b27253bdea7452sewardj               fp_push();
401089cd09353a584000edaaa61558b27253bdea7452sewardj               put_ST(0, unop(Iop_F32toF64,
40118f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj                              loadLE(Ity_F32, mkexpr(addr))));
401289cd09353a584000edaaa61558b27253bdea7452sewardj               break;
401389cd09353a584000edaaa61558b27253bdea7452sewardj
4014588ea765122c1ecb97991eea513b12504e35d55esewardj            case 2: /* FST single-real */
401533dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fsts %s\n", dis_buf);
40163bca906f6e715c544eb49c278bedef093c14c0d7sewardj               storeLE(mkexpr(addr),
40173bca906f6e715c544eb49c278bedef093c14c0d7sewardj                       binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4018588ea765122c1ecb97991eea513b12504e35d55esewardj               break;
4019588ea765122c1ecb97991eea513b12504e35d55esewardj
402089cd09353a584000edaaa61558b27253bdea7452sewardj            case 3: /* FSTP single-real */
402133dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fstps %s\n", dis_buf);
40223bca906f6e715c544eb49c278bedef093c14c0d7sewardj               storeLE(mkexpr(addr),
40233bca906f6e715c544eb49c278bedef093c14c0d7sewardj                       binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
40245bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fp_pop();
402589cd09353a584000edaaa61558b27253bdea7452sewardj               break;
402689cd09353a584000edaaa61558b27253bdea7452sewardj
4027d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj            case 4: { /* FLDENV m28 */
40287df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* Uses dirty helper:
40296ef84bed9bb3af22060eb1759788034602bbcc88florian                     VexEmNote x86g_do_FLDENV ( VexGuestX86State*, HWord ) */
40307df596b1e36840e2d74c90aa55589934add61ccfsewardj               IRTemp   ew = newTemp(Ity_I32);
40317df596b1e36840e2d74c90aa55589934add61ccfsewardj               IRDirty* d  = unsafeIRDirty_0_N (
40327df596b1e36840e2d74c90aa55589934add61ccfsewardj                                0/*regparms*/,
40337df596b1e36840e2d74c90aa55589934add61ccfsewardj                                "x86g_dirtyhelper_FLDENV",
40347df596b1e36840e2d74c90aa55589934add61ccfsewardj                                &x86g_dirtyhelper_FLDENV,
4035ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                                mkIRExprVec_2( IRExpr_GSPTR(), mkexpr(addr) )
40367df596b1e36840e2d74c90aa55589934add61ccfsewardj                             );
403774142b8c8d5d3b3db17d744f5d5fb80f548bcf74sewardj               d->tmp   = ew;
40387df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* declare we're reading memory */
40397df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->mFx   = Ifx_Read;
40407df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->mAddr = mkexpr(addr);
40417df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->mSize = 28;
40427df596b1e36840e2d74c90aa55589934add61ccfsewardj
40437df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* declare we're writing guest state */
404446813fc413b6e3c7b0e25525254bdd22a6672588sewardj               d->nFxState = 4;
4045c9069f2908814843e9a4da00da9c8905440195a6sewardj               vex_bzero(&d->fxState, sizeof(d->fxState));
40467df596b1e36840e2d74c90aa55589934add61ccfsewardj
40477df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[0].fx     = Ifx_Write;
40487df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[0].offset = OFFB_FTOP;
40497df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[0].size   = sizeof(UInt);
40507df596b1e36840e2d74c90aa55589934add61ccfsewardj
40517df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[1].fx     = Ifx_Write;
405246813fc413b6e3c7b0e25525254bdd22a6672588sewardj               d->fxState[1].offset = OFFB_FPTAGS;
405346813fc413b6e3c7b0e25525254bdd22a6672588sewardj               d->fxState[1].size   = 8 * sizeof(UChar);
40547df596b1e36840e2d74c90aa55589934add61ccfsewardj
40557df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[2].fx     = Ifx_Write;
405646813fc413b6e3c7b0e25525254bdd22a6672588sewardj               d->fxState[2].offset = OFFB_FPROUND;
405746813fc413b6e3c7b0e25525254bdd22a6672588sewardj               d->fxState[2].size   = sizeof(UInt);
40587df596b1e36840e2d74c90aa55589934add61ccfsewardj
40597df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[3].fx     = Ifx_Write;
406046813fc413b6e3c7b0e25525254bdd22a6672588sewardj               d->fxState[3].offset = OFFB_FC3210;
40617df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[3].size   = sizeof(UInt);
40627df596b1e36840e2d74c90aa55589934add61ccfsewardj
40637df596b1e36840e2d74c90aa55589934add61ccfsewardj               stmt( IRStmt_Dirty(d) );
40647df596b1e36840e2d74c90aa55589934add61ccfsewardj
40657df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* ew contains any emulation warning we may need to
40667df596b1e36840e2d74c90aa55589934add61ccfsewardj                  issue.  If needed, side-exit to the next insn,
40677df596b1e36840e2d74c90aa55589934add61ccfsewardj                  reporting the warning, so that Valgrind's dispatcher
40687df596b1e36840e2d74c90aa55589934add61ccfsewardj                  sees the warning. */
40697df596b1e36840e2d74c90aa55589934add61ccfsewardj               put_emwarn( mkexpr(ew) );
40707df596b1e36840e2d74c90aa55589934add61ccfsewardj               stmt(
40717df596b1e36840e2d74c90aa55589934add61ccfsewardj                  IRStmt_Exit(
40727df596b1e36840e2d74c90aa55589934add61ccfsewardj                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
40737df596b1e36840e2d74c90aa55589934add61ccfsewardj                     Ijk_EmWarn,
4074c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
4075c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     OFFB_EIP
40767df596b1e36840e2d74c90aa55589934add61ccfsewardj                  )
40777df596b1e36840e2d74c90aa55589934add61ccfsewardj               );
40787df596b1e36840e2d74c90aa55589934add61ccfsewardj
407933dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldenv %s\n", dis_buf);
40807df596b1e36840e2d74c90aa55589934add61ccfsewardj               break;
40817df596b1e36840e2d74c90aa55589934add61ccfsewardj            }
40827df596b1e36840e2d74c90aa55589934add61ccfsewardj
4083893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj            case 5: {/* FLDCW */
4084893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               /* The only thing we observe in the control word is the
4085d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                  rounding mode.  Therefore, pass the 16-bit value
4086d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                  (x87 native-format control word) to a clean helper,
4087d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                  getting back a 64-bit value, the lower half of which
4088d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                  is the FPROUND value to store, and the upper half of
4089d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                  which is the emulation-warning token which may be
4090d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                  generated.
4091893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               */
4092893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               /* ULong x86h_check_fldcw ( UInt ); */
4093893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               IRTemp t64 = newTemp(Ity_I64);
4094893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               IRTemp ew = newTemp(Ity_I32);
409533dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldcw %s\n", dis_buf);
4096893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               assign( t64, mkIRExprCCall(
4097893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                               Ity_I64, 0/*regparms*/,
40983bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                               "x86g_check_fldcw",
40993bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                               &x86g_check_fldcw,
4100893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                               mkIRExprVec_1(
4101893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                                  unop( Iop_16Uto32,
4102893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                                        loadLE(Ity_I16, mkexpr(addr)))
4103893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                               )
4104893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                            )
4105893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                     );
4106893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj
4107d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj               put_fpround( unop(Iop_64to32, mkexpr(t64)) );
4108893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
4109893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               put_emwarn( mkexpr(ew) );
4110893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               /* Finally, if an emulation warning was reported,
4111893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  side-exit to the next insn, reporting the warning,
4112893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  so that Valgrind's dispatcher sees the warning. */
4113893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               stmt(
4114893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  IRStmt_Exit(
4115893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4116893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                     Ijk_EmWarn,
4117c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
4118c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     OFFB_EIP
4119893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  )
4120893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               );
412189cd09353a584000edaaa61558b27253bdea7452sewardj               break;
4122893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj            }
412389cd09353a584000edaaa61558b27253bdea7452sewardj
41247df596b1e36840e2d74c90aa55589934add61ccfsewardj            case 6: { /* FNSTENV m28 */
41257df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* Uses dirty helper:
41264017a3b223ee0ae98f6068e5eaaee0e3151d482asewardj                     void x86g_do_FSTENV ( VexGuestX86State*, HWord ) */
41277df596b1e36840e2d74c90aa55589934add61ccfsewardj               IRDirty* d = unsafeIRDirty_0_N (
41287df596b1e36840e2d74c90aa55589934add61ccfsewardj                               0/*regparms*/,
41297df596b1e36840e2d74c90aa55589934add61ccfsewardj                               "x86g_dirtyhelper_FSTENV",
41307df596b1e36840e2d74c90aa55589934add61ccfsewardj                               &x86g_dirtyhelper_FSTENV,
4131ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                               mkIRExprVec_2( IRExpr_GSPTR(), mkexpr(addr) )
41327df596b1e36840e2d74c90aa55589934add61ccfsewardj                            );
41337df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* declare we're writing memory */
41347df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->mFx   = Ifx_Write;
41357df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->mAddr = mkexpr(addr);
41367df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->mSize = 28;
41377df596b1e36840e2d74c90aa55589934add61ccfsewardj
41387df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* declare we're reading guest state */
41397df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->nFxState = 4;
4140c9069f2908814843e9a4da00da9c8905440195a6sewardj               vex_bzero(&d->fxState, sizeof(d->fxState));
41417df596b1e36840e2d74c90aa55589934add61ccfsewardj
41427df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[0].fx     = Ifx_Read;
41437df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[0].offset = OFFB_FTOP;
41447df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[0].size   = sizeof(UInt);
41457df596b1e36840e2d74c90aa55589934add61ccfsewardj
41467df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[1].fx     = Ifx_Read;
41477df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[1].offset = OFFB_FPTAGS;
41487df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[1].size   = 8 * sizeof(UChar);
41497df596b1e36840e2d74c90aa55589934add61ccfsewardj
41507df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[2].fx     = Ifx_Read;
41517df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[2].offset = OFFB_FPROUND;
41527df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[2].size   = sizeof(UInt);
41537df596b1e36840e2d74c90aa55589934add61ccfsewardj
41547df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[3].fx     = Ifx_Read;
41557df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[3].offset = OFFB_FC3210;
41567df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[3].size   = sizeof(UInt);
41577df596b1e36840e2d74c90aa55589934add61ccfsewardj
41587df596b1e36840e2d74c90aa55589934add61ccfsewardj               stmt( IRStmt_Dirty(d) );
41597df596b1e36840e2d74c90aa55589934add61ccfsewardj
416033dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fnstenv %s\n", dis_buf);
41617df596b1e36840e2d74c90aa55589934add61ccfsewardj               break;
41627df596b1e36840e2d74c90aa55589934add61ccfsewardj            }
41637df596b1e36840e2d74c90aa55589934add61ccfsewardj
4164588ea765122c1ecb97991eea513b12504e35d55esewardj            case 7: /* FNSTCW */
4165893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj              /* Fake up a native x87 FPU control word.  The only
4166d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                 thing it depends on is FPROUND[1:0], so call a clean
4167893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                 helper to cook it up. */
4168d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj               /* UInt x86h_create_fpucw ( UInt fpround ) */
416933dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fnstcw %s\n", dis_buf);
4170893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               storeLE(
4171893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  mkexpr(addr),
4172893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  unop( Iop_32to16,
4173893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                        mkIRExprCCall(
4174893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                           Ity_I32, 0/*regp*/,
41753bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                           "x86g_create_fpucw", &x86g_create_fpucw,
4176d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                           mkIRExprVec_1( get_fpround() )
4177893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                        )
4178893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  )
4179893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               );
418089cd09353a584000edaaa61558b27253bdea7452sewardj               break;
418189cd09353a584000edaaa61558b27253bdea7452sewardj
418289cd09353a584000edaaa61558b27253bdea7452sewardj            default:
4183b173774421d015736c2316b5e6e998e7de545a5cflorian               vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
418489cd09353a584000edaaa61558b27253bdea7452sewardj               vex_printf("first_opcode == 0xD9\n");
418589cd09353a584000edaaa61558b27253bdea7452sewardj               goto decode_fail;
418689cd09353a584000edaaa61558b27253bdea7452sewardj         }
418789cd09353a584000edaaa61558b27253bdea7452sewardj
4188bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj      } else {
4189bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         delta++;
4190bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         switch (modrm) {
419189cd09353a584000edaaa61558b27253bdea7452sewardj
4192bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj            case 0xC0 ... 0xC7: /* FLD %st(?) */
4193a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               r_src = (UInt)modrm - 0xC0;
4194b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fld %%st(%u)\n", r_src);
41955bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               t1 = newTemp(Ity_F64);
41965bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               assign(t1, get_ST(r_src));
41975bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fp_push();
41985bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               put_ST(0, mkexpr(t1));
4199bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               break;
4200bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj
420189cd09353a584000edaaa61558b27253bdea7452sewardj            case 0xC8 ... 0xCF: /* FXCH %st(?) */
420289cd09353a584000edaaa61558b27253bdea7452sewardj               r_src = (UInt)modrm - 0xC8;
4203b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fxch %%st(%u)\n", r_src);
420489cd09353a584000edaaa61558b27253bdea7452sewardj               t1 = newTemp(Ity_F64);
420589cd09353a584000edaaa61558b27253bdea7452sewardj               t2 = newTemp(Ity_F64);
420689cd09353a584000edaaa61558b27253bdea7452sewardj               assign(t1, get_ST(0));
420789cd09353a584000edaaa61558b27253bdea7452sewardj               assign(t2, get_ST(r_src));
420889cd09353a584000edaaa61558b27253bdea7452sewardj               put_ST_UNCHECKED(0, mkexpr(t2));
420989cd09353a584000edaaa61558b27253bdea7452sewardj               put_ST_UNCHECKED(r_src, mkexpr(t1));
421089cd09353a584000edaaa61558b27253bdea7452sewardj               break;
421189cd09353a584000edaaa61558b27253bdea7452sewardj
4212cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 0xE0: /* FCHS */
4213cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               DIP("fchs\n");
4214cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4215cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4216cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
4217883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 0xE1: /* FABS */
4218883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               DIP("fabs\n");
4219883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4220883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               break;
4221883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
42221c31877a29646fb6f902de217ae8f62bccfeda7dsewardj            case 0xE4: /* FTST */
42231c31877a29646fb6f902de217ae8f62bccfeda7dsewardj               DIP("ftst\n");
42241c31877a29646fb6f902de217ae8f62bccfeda7dsewardj               /* This forces C1 to zero, which isn't right. */
42251c31877a29646fb6f902de217ae8f62bccfeda7dsewardj               /* Well, in fact the Intel docs say (bizarrely): "C1 is
42261c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                  set to 0 if stack underflow occurred; otherwise, set
42271c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                  to 0" which is pretty nonsensical.  I guess it's a
42281c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                   typo. */
42291c31877a29646fb6f902de217ae8f62bccfeda7dsewardj               put_C3210(
42301c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                   binop( Iop_And32,
42311c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                          binop(Iop_Shl32,
42321c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                                binop(Iop_CmpF64,
42331c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                                      get_ST(0),
42341c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                                      IRExpr_Const(IRConst_F64i(0x0ULL))),
42351c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                                mkU8(8)),
42361c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                          mkU32(0x4500)
42371c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                   ));
42381c31877a29646fb6f902de217ae8f62bccfeda7dsewardj               break;
42391c31877a29646fb6f902de217ae8f62bccfeda7dsewardj
4240883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 0xE5: { /* FXAM */
4241883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               /* This is an interesting one.  It examines %st(0),
4242883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                  regardless of whether the tag says it's empty or not.
4243883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                  Here, just pass both the tag (in our format) and the
4244883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                  value (as a double, actually a ULong) to a helper
4245883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                  function. */
4246f96552617c82834ece36184e674e249faa899b2fsewardj               IRExpr** args
4247f96552617c82834ece36184e674e249faa899b2fsewardj                  = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
4248f96552617c82834ece36184e674e249faa899b2fsewardj                                   unop(Iop_ReinterpF64asI64,
4249f96552617c82834ece36184e674e249faa899b2fsewardj                                        get_ST_UNCHECKED(0)) );
4250f96552617c82834ece36184e674e249faa899b2fsewardj               put_C3210(mkIRExprCCall(
42518ea867b06de73d909c29e243407713c291c8414esewardj                            Ity_I32,
4252f96552617c82834ece36184e674e249faa899b2fsewardj                            0/*regparm*/,
42532a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                            "x86g_calculate_FXAM", &x86g_calculate_FXAM,
42548ea867b06de73d909c29e243407713c291c8414esewardj                            args
42558ea867b06de73d909c29e243407713c291c8414esewardj                        ));
425633dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fxam\n");
4257883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               break;
4258883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            }
4259883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
4260883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 0xE8: /* FLD1 */
426133dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fld1\n");
4262ce646f23d71ac432c340667387aa4a5ce7d18099sewardj               fp_push();
42639c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
42649c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
4265ce646f23d71ac432c340667387aa4a5ce7d18099sewardj               break;
4266ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
426737158719b222a3776df257a80c8ce44d810fae82sewardj            case 0xE9: /* FLDL2T */
426833dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldl2t\n");
426937158719b222a3776df257a80c8ce44d810fae82sewardj               fp_push();
42709c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
42719c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
427237158719b222a3776df257a80c8ce44d810fae82sewardj               break;
427337158719b222a3776df257a80c8ce44d810fae82sewardj
42748308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            case 0xEA: /* FLDL2E */
427533dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldl2e\n");
42768308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               fp_push();
42779c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
42789c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
42798308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               break;
42808308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
4281a0d48d648efc6948d5319c5b22705b397ac664b6sewardj            case 0xEB: /* FLDPI */
428233dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldpi\n");
4283a0d48d648efc6948d5319c5b22705b397ac664b6sewardj               fp_push();
42849c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
42859c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
4286a0d48d648efc6948d5319c5b22705b397ac664b6sewardj               break;
4287a0d48d648efc6948d5319c5b22705b397ac664b6sewardj
4288db199620ca3945e9f43d4738c159ce1860142a55sewardj            case 0xEC: /* FLDLG2 */
428933dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldlg2\n");
4290db199620ca3945e9f43d4738c159ce1860142a55sewardj               fp_push();
42919c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
42929c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
4293db199620ca3945e9f43d4738c159ce1860142a55sewardj               break;
4294db199620ca3945e9f43d4738c159ce1860142a55sewardj
4295db199620ca3945e9f43d4738c159ce1860142a55sewardj            case 0xED: /* FLDLN2 */
429633dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldln2\n");
4297db199620ca3945e9f43d4738c159ce1860142a55sewardj               fp_push();
42989c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
42999c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
4300db199620ca3945e9f43d4738c159ce1860142a55sewardj               break;
4301db199620ca3945e9f43d4738c159ce1860142a55sewardj
4302a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj            case 0xEE: /* FLDZ */
430333dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldz\n");
4304207557ab2ea38239b670785c976b89d50bbb0eccsewardj               fp_push();
43059c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
43069c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
4307a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               break;
4308a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
430906c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj            case 0xF0: /* F2XM1 */
431006c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               DIP("f2xm1\n");
4311f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj               put_ST_UNCHECKED(0,
4312f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  binop(Iop_2xm1F64,
4313f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4314f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(0)));
431506c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               break;
431606c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj
431752ace3ed99ccb7d0e4c64dc06381e407a8bfcf1dsewardj            case 0xF1: /* FYL2X */
431852ace3ed99ccb7d0e4c64dc06381e407a8bfcf1dsewardj               DIP("fyl2x\n");
4319f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj               put_ST_UNCHECKED(1,
4320f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(Iop_Yl2xF64,
4321f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4322f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(1),
4323f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(0)));
432452ace3ed99ccb7d0e4c64dc06381e407a8bfcf1dsewardj               fp_pop();
432552ace3ed99ccb7d0e4c64dc06381e407a8bfcf1dsewardj               break;
432652ace3ed99ccb7d0e4c64dc06381e407a8bfcf1dsewardj
4327e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj            case 0xF2: { /* FPTAN */
4328e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               DIP("fptan\n");
4329e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp argD = newTemp(Ity_F64);
4330e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               assign(argD, get_ST(0));
4331e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4332e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp resD = newTemp(Ity_F64);
4333e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               assign(resD,
4334e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                  IRExpr_ITE(
4335e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(argOK),
4336e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     binop(Iop_TanF64,
4337e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                           get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4338e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                           mkexpr(argD)),
4339e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(argD))
4340e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               );
4341e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               put_ST_UNCHECKED(0, mkexpr(resD));
4342e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               /* Conditionally push 1.0 on the stack, if the arg is
4343e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                  in range */
4344e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               maybe_fp_push(argOK);
4345e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               maybe_put_ST(argOK, 0,
4346e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                            IRExpr_Const(IRConst_F64(1.0)));
4347e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               set_C2( binop(Iop_Xor32,
4348e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                             unop(Iop_1Uto32, mkexpr(argOK)),
4349e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                             mkU32(1)) );
435099016a7b2d31c50a02b4a3ae8c7b0cf4de2c22cfsewardj               break;
4351e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj            }
435299016a7b2d31c50a02b4a3ae8c7b0cf4de2c22cfsewardj
4353cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 0xF3: /* FPATAN */
4354cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               DIP("fpatan\n");
4355f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj               put_ST_UNCHECKED(1,
4356f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(Iop_AtanF64,
4357f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4358f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(1),
4359f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(0)));
4360cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_pop();
4361cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4362cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
4363f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj            case 0xF4: { /* FXTRACT */
4364fda10af6bee6565643e8ff474b828479ba873080sewardj               IRTemp argF = newTemp(Ity_F64);
4365fda10af6bee6565643e8ff474b828479ba873080sewardj               IRTemp sigF = newTemp(Ity_F64);
4366fda10af6bee6565643e8ff474b828479ba873080sewardj               IRTemp expF = newTemp(Ity_F64);
4367fda10af6bee6565643e8ff474b828479ba873080sewardj               IRTemp argI = newTemp(Ity_I64);
4368fda10af6bee6565643e8ff474b828479ba873080sewardj               IRTemp sigI = newTemp(Ity_I64);
4369fda10af6bee6565643e8ff474b828479ba873080sewardj               IRTemp expI = newTemp(Ity_I64);
4370fda10af6bee6565643e8ff474b828479ba873080sewardj               DIP("fxtract\n");
4371fda10af6bee6565643e8ff474b828479ba873080sewardj               assign( argF, get_ST(0) );
4372fda10af6bee6565643e8ff474b828479ba873080sewardj               assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
4373fda10af6bee6565643e8ff474b828479ba873080sewardj               assign( sigI,
4374879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                       mkIRExprCCall(
4375879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          Ity_I64, 0/*regparms*/,
4376879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          "x86amd64g_calculate_FXTRACT",
4377879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          &x86amd64g_calculate_FXTRACT,
4378879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          mkIRExprVec_2( mkexpr(argI),
4379879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                                         mkIRExpr_HWord(0)/*sig*/ ))
4380879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj               );
4381fda10af6bee6565643e8ff474b828479ba873080sewardj               assign( expI,
4382879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                       mkIRExprCCall(
4383879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          Ity_I64, 0/*regparms*/,
4384879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          "x86amd64g_calculate_FXTRACT",
4385879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          &x86amd64g_calculate_FXTRACT,
4386879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          mkIRExprVec_2( mkexpr(argI),
4387879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                                         mkIRExpr_HWord(1)/*exp*/ ))
4388879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj               );
4389fda10af6bee6565643e8ff474b828479ba873080sewardj               assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
4390fda10af6bee6565643e8ff474b828479ba873080sewardj               assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
4391fda10af6bee6565643e8ff474b828479ba873080sewardj               /* exponent */
4392fda10af6bee6565643e8ff474b828479ba873080sewardj               put_ST_UNCHECKED(0, mkexpr(expF) );
4393fda10af6bee6565643e8ff474b828479ba873080sewardj               fp_push();
4394fda10af6bee6565643e8ff474b828479ba873080sewardj               /* significand */
4395fda10af6bee6565643e8ff474b828479ba873080sewardj               put_ST(0, mkexpr(sigF) );
4396fda10af6bee6565643e8ff474b828479ba873080sewardj               break;
4397fda10af6bee6565643e8ff474b828479ba873080sewardj            }
4398fda10af6bee6565643e8ff474b828479ba873080sewardj
4399442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj            case 0xF5: { /* FPREM1 -- IEEE compliant */
4400442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               IRTemp a1 = newTemp(Ity_F64);
4401442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               IRTemp a2 = newTemp(Ity_F64);
4402442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               DIP("fprem1\n");
4403442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               /* Do FPREM1 twice, once to get the remainder, and once
4404442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj                  to get the C3210 flag values. */
4405442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               assign( a1, get_ST(0) );
4406442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               assign( a2, get_ST(1) );
4407f47286e34e0d2899b47d64205816866a16a13ba4sewardj               put_ST_UNCHECKED(0,
4408f47286e34e0d2899b47d64205816866a16a13ba4sewardj                  triop(Iop_PRem1F64,
4409f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4410f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a1),
4411f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a2)));
4412f47286e34e0d2899b47d64205816866a16a13ba4sewardj               put_C3210(
4413f47286e34e0d2899b47d64205816866a16a13ba4sewardj                  triop(Iop_PRem1C3210F64,
4414f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4415f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a1),
4416f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a2)) );
4417442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               break;
4418442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj            }
4419442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj
4420feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 0xF7: /* FINCSTP */
4421feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               DIP("fprem\n");
4422feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4423feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               break;
4424feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
442546de4076882d6a44ff0f76bd8b70c3d89b050293sewardj            case 0xF8: { /* FPREM -- not IEEE compliant */
442646de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               IRTemp a1 = newTemp(Ity_F64);
442746de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               IRTemp a2 = newTemp(Ity_F64);
442846de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               DIP("fprem\n");
442946de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               /* Do FPREM twice, once to get the remainder, and once
443046de4076882d6a44ff0f76bd8b70c3d89b050293sewardj                  to get the C3210 flag values. */
443146de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               assign( a1, get_ST(0) );
443246de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               assign( a2, get_ST(1) );
4433f47286e34e0d2899b47d64205816866a16a13ba4sewardj               put_ST_UNCHECKED(0,
4434f47286e34e0d2899b47d64205816866a16a13ba4sewardj                  triop(Iop_PRemF64,
4435f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4436f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a1),
4437f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a2)));
4438f47286e34e0d2899b47d64205816866a16a13ba4sewardj               put_C3210(
4439f47286e34e0d2899b47d64205816866a16a13ba4sewardj                  triop(Iop_PRemC3210F64,
4440f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4441f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a1),
4442f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a2)) );
444346de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               break;
444446de4076882d6a44ff0f76bd8b70c3d89b050293sewardj            }
444546de4076882d6a44ff0f76bd8b70c3d89b050293sewardj
44468308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            case 0xF9: /* FYL2XP1 */
44478308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               DIP("fyl2xp1\n");
4448f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj               put_ST_UNCHECKED(1,
4449f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(Iop_Yl2xp1F64,
4450f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4451f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(1),
4452f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(0)));
44538308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               fp_pop();
44548308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               break;
44558308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
4456c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj            case 0xFA: /* FSQRT */
4457c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               DIP("fsqrt\n");
4458f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj               put_ST_UNCHECKED(0,
4459f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  binop(Iop_SqrtF64,
4460f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4461f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(0)));
4462c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               break;
4463c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj
4464519d66fc0e4f16b120079bc651862e49f154da62sewardj            case 0xFB: { /* FSINCOS */
4465519d66fc0e4f16b120079bc651862e49f154da62sewardj               DIP("fsincos\n");
4466e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp argD = newTemp(Ity_F64);
4467e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               assign(argD, get_ST(0));
4468e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4469e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp resD = newTemp(Ity_F64);
4470e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               assign(resD,
4471e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                  IRExpr_ITE(
4472e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(argOK),
4473e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     binop(Iop_SinF64,
4474e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                           get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4475e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                           mkexpr(argD)),
4476e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(argD))
4477e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               );
4478e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               put_ST_UNCHECKED(0, mkexpr(resD));
4479e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               /* Conditionally push the cos value on the stack, if
4480e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                  the arg is in range */
4481e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               maybe_fp_push(argOK);
4482e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               maybe_put_ST(argOK, 0,
4483f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  binop(Iop_CosF64,
4484f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4485e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                        mkexpr(argD)));
4486e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               set_C2( binop(Iop_Xor32,
4487e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                             unop(Iop_1Uto32, mkexpr(argOK)),
4488e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                             mkU32(1)) );
4489519d66fc0e4f16b120079bc651862e49f154da62sewardj               break;
4490519d66fc0e4f16b120079bc651862e49f154da62sewardj            }
4491519d66fc0e4f16b120079bc651862e49f154da62sewardj
4492e6709111d4af7becab76be5971eea568074174cdsewardj            case 0xFC: /* FRNDINT */
4493e6709111d4af7becab76be5971eea568074174cdsewardj               DIP("frndint\n");
4494e6709111d4af7becab76be5971eea568074174cdsewardj               put_ST_UNCHECKED(0,
4495b183b8571b4ec98866ce2b3653a9d066cf5f16f4sewardj                  binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
4496e6709111d4af7becab76be5971eea568074174cdsewardj               break;
4497e6709111d4af7becab76be5971eea568074174cdsewardj
449806c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj            case 0xFD: /* FSCALE */
449906c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               DIP("fscale\n");
4500f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj               put_ST_UNCHECKED(0,
4501f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(Iop_ScaleF64,
4502f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4503f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(0),
4504f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(1)));
450506c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               break;
450606c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj
4507e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj            case 0xFE:   /* FSIN */
4508e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj            case 0xFF: { /* FCOS */
4509e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               Bool isSIN = modrm == 0xFE;
4510e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               DIP("%s\n", isSIN ? "fsin" : "fcos");
4511e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp argD = newTemp(Ity_F64);
4512e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               assign(argD, get_ST(0));
4513e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4514e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp resD = newTemp(Ity_F64);
4515e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               assign(resD,
4516e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                  IRExpr_ITE(
4517e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(argOK),
4518e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     binop(isSIN ? Iop_SinF64 : Iop_CosF64,
4519e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                           get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4520e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                           mkexpr(argD)),
4521e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(argD))
4522e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               );
4523e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               put_ST_UNCHECKED(0, mkexpr(resD));
4524e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               set_C2( binop(Iop_Xor32,
4525e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                             unop(Iop_1Uto32, mkexpr(argOK)),
4526e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                             mkU32(1)) );
4527cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4528e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj            }
4529cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
4530bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj            default:
4531bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               goto decode_fail;
4532bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         }
4533bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj      }
4534d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
4535d1725d18b61bf7912a9099686179faef5815dba1sewardj
4536d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4537d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
4538d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xDA) {
4539bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj
4540bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj      if (modrm < 0xC0) {
4541bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj
4542feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
4543bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj            specifies an address. */
4544ce646f23d71ac432c340667387aa4a5ce7d18099sewardj         IROp   fop;
4545bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4546bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         delta += len;
4547bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         switch (gregOfRM(modrm)) {
4548ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
4549db199620ca3945e9f43d4738c159ce1860142a55sewardj            case 0: /* FIADD m32int */ /* ST(0) += m32int */
455033dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fiaddl %s\n", dis_buf);
45515bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fop = Iop_AddF64;
45525bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               goto do_fop_m32;
4553db199620ca3945e9f43d4738c159ce1860142a55sewardj
4554207557ab2ea38239b670785c976b89d50bbb0eccsewardj            case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
455533dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fimull %s\n", dis_buf);
45565bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fop = Iop_MulF64;
45575bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               goto do_fop_m32;
4558ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
4559071895fca57b5b710485a4951fef12317e337064sewardj            case 2: /* FICOM m32int */
4560071895fca57b5b710485a4951fef12317e337064sewardj               DIP("ficoml %s\n", dis_buf);
4561071895fca57b5b710485a4951fef12317e337064sewardj               /* This forces C1 to zero, which isn't right. */
4562071895fca57b5b710485a4951fef12317e337064sewardj               put_C3210(
4563071895fca57b5b710485a4951fef12317e337064sewardj                   binop( Iop_And32,
4564071895fca57b5b710485a4951fef12317e337064sewardj                          binop(Iop_Shl32,
4565071895fca57b5b710485a4951fef12317e337064sewardj                                binop(Iop_CmpF64,
4566071895fca57b5b710485a4951fef12317e337064sewardj                                      get_ST(0),
45676c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                                      unop(Iop_I32StoF64,
4568071895fca57b5b710485a4951fef12317e337064sewardj                                           loadLE(Ity_I32,mkexpr(addr)))),
4569071895fca57b5b710485a4951fef12317e337064sewardj                                mkU8(8)),
4570071895fca57b5b710485a4951fef12317e337064sewardj                          mkU32(0x4500)
4571071895fca57b5b710485a4951fef12317e337064sewardj                   ));
4572071895fca57b5b710485a4951fef12317e337064sewardj               break;
4573071895fca57b5b710485a4951fef12317e337064sewardj
4574071895fca57b5b710485a4951fef12317e337064sewardj            case 3: /* FICOMP m32int */
4575071895fca57b5b710485a4951fef12317e337064sewardj               DIP("ficompl %s\n", dis_buf);
4576071895fca57b5b710485a4951fef12317e337064sewardj               /* This forces C1 to zero, which isn't right. */
4577071895fca57b5b710485a4951fef12317e337064sewardj               put_C3210(
4578071895fca57b5b710485a4951fef12317e337064sewardj                   binop( Iop_And32,
4579071895fca57b5b710485a4951fef12317e337064sewardj                          binop(Iop_Shl32,
4580071895fca57b5b710485a4951fef12317e337064sewardj                                binop(Iop_CmpF64,
4581071895fca57b5b710485a4951fef12317e337064sewardj                                      get_ST(0),
45826c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                                      unop(Iop_I32StoF64,
4583071895fca57b5b710485a4951fef12317e337064sewardj                                           loadLE(Ity_I32,mkexpr(addr)))),
4584071895fca57b5b710485a4951fef12317e337064sewardj                                mkU8(8)),
4585071895fca57b5b710485a4951fef12317e337064sewardj                          mkU32(0x4500)
4586071895fca57b5b710485a4951fef12317e337064sewardj                   ));
4587071895fca57b5b710485a4951fef12317e337064sewardj               fp_pop();
4588071895fca57b5b710485a4951fef12317e337064sewardj               break;
4589071895fca57b5b710485a4951fef12317e337064sewardj
4590ce646f23d71ac432c340667387aa4a5ce7d18099sewardj            case 4: /* FISUB m32int */ /* ST(0) -= m32int */
459133dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fisubl %s\n", dis_buf);
45925bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fop = Iop_SubF64;
45935bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               goto do_fop_m32;
4594ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
45958308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
459633dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fisubrl %s\n", dis_buf);
45975bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fop = Iop_SubF64;
45985bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               goto do_foprev_m32;
45998308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
4600ce646f23d71ac432c340667387aa4a5ce7d18099sewardj            case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
460136917e92816cfd8c998e56f774709d953967b2a6sewardj               DIP("fidivl %s\n", dis_buf);
46025bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fop = Iop_DivF64;
46035bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               goto do_fop_m32;
4604ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
4605c4eaff3aa358fc5c73b534c7e78366555184244fsewardj            case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
460633dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fidivrl %s\n", dis_buf);
46075bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fop = Iop_DivF64;
46085bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               goto do_foprev_m32;
4609c4eaff3aa358fc5c73b534c7e78366555184244fsewardj
4610ce646f23d71ac432c340667387aa4a5ce7d18099sewardj            do_fop_m32:
4611207557ab2ea38239b670785c976b89d50bbb0eccsewardj               put_ST_UNCHECKED(0,
4612f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(fop,
4613f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4614207557ab2ea38239b670785c976b89d50bbb0eccsewardj                        get_ST(0),
46156c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        unop(Iop_I32StoF64,
461689cd09353a584000edaaa61558b27253bdea7452sewardj                             loadLE(Ity_I32, mkexpr(addr)))));
4617bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               break;
4618bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj
4619c4eaff3aa358fc5c73b534c7e78366555184244fsewardj            do_foprev_m32:
4620c4eaff3aa358fc5c73b534c7e78366555184244fsewardj               put_ST_UNCHECKED(0,
4621f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(fop,
4622f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
46236c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        unop(Iop_I32StoF64,
4624c4eaff3aa358fc5c73b534c7e78366555184244fsewardj                             loadLE(Ity_I32, mkexpr(addr))),
4625c4eaff3aa358fc5c73b534c7e78366555184244fsewardj                        get_ST(0)));
4626c4eaff3aa358fc5c73b534c7e78366555184244fsewardj               break;
4627c4eaff3aa358fc5c73b534c7e78366555184244fsewardj
4628bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj            default:
4629b173774421d015736c2316b5e6e998e7de545a5cflorian               vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
4630bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               vex_printf("first_opcode == 0xDA\n");
4631bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               goto decode_fail;
4632bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         }
46334cb918d355cef4e7640d374346852db4556f3524sewardj
4634bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj      } else {
4635bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
4636bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         delta++;
4637bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         switch (modrm) {
4638bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
4639519d66fc0e4f16b120079bc651862e49f154da62sewardj            case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4640519d66fc0e4f16b120079bc651862e49f154da62sewardj               r_src = (UInt)modrm - 0xC0;
4641b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fcmovb %%st(%u), %%st(0)\n", r_src);
4642519d66fc0e4f16b120079bc651862e49f154da62sewardj               put_ST_UNCHECKED(0,
464399dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4644009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondB),
464599dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
4646519d66fc0e4f16b120079bc651862e49f154da62sewardj               break;
4647519d66fc0e4f16b120079bc651862e49f154da62sewardj
46483fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
46493fd5e570294226c643f974b438225e3f09a82f4fsewardj               r_src = (UInt)modrm - 0xC8;
4650b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fcmovz %%st(%u), %%st(0)\n", r_src);
46515bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               put_ST_UNCHECKED(0,
465299dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4653009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondZ),
465499dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
46553fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
46563fd5e570294226c643f974b438225e3f09a82f4fsewardj
4657519d66fc0e4f16b120079bc651862e49f154da62sewardj            case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4658519d66fc0e4f16b120079bc651862e49f154da62sewardj               r_src = (UInt)modrm - 0xD0;
4659b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fcmovbe %%st(%u), %%st(0)\n", r_src);
4660519d66fc0e4f16b120079bc651862e49f154da62sewardj               put_ST_UNCHECKED(0,
466199dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4662009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondBE),
466399dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
4664519d66fc0e4f16b120079bc651862e49f154da62sewardj               break;
4665519d66fc0e4f16b120079bc651862e49f154da62sewardj
46668253ad3c3696f46b30daf66003f7649abe70286dsewardj            case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
46678253ad3c3696f46b30daf66003f7649abe70286dsewardj               r_src = (UInt)modrm - 0xD8;
4668b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fcmovu %%st(%u), %%st(0)\n", r_src);
46698253ad3c3696f46b30daf66003f7649abe70286dsewardj               put_ST_UNCHECKED(0,
467099dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4671009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondP),
467299dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
46738253ad3c3696f46b30daf66003f7649abe70286dsewardj               break;
46748253ad3c3696f46b30daf66003f7649abe70286dsewardj
4675bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xE9: /* FUCOMPP %st(0),%st(1) */
4676bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               DIP("fucompp %%st(0),%%st(1)\n");
4677c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               /* This forces C1 to zero, which isn't right. */
4678c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               put_C3210(
4679c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                   binop( Iop_And32,
4680c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                          binop(Iop_Shl32,
4681c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                                binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4682c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                                mkU8(8)),
4683c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                          mkU32(0x4500)
4684c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                   ));
4685bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_pop();
4686bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_pop();
4687bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
4688bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
46895bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            default:
4690bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               goto decode_fail;
46915bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         }
4692bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
4693bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj      }
4694d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
4695d1725d18b61bf7912a9099686179faef5815dba1sewardj
4696d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4697d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
4698d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xDB) {
469989cd09353a584000edaaa61558b27253bdea7452sewardj      if (modrm < 0xC0) {
470089cd09353a584000edaaa61558b27253bdea7452sewardj
4701feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
470289cd09353a584000edaaa61558b27253bdea7452sewardj            specifies an address. */
470389cd09353a584000edaaa61558b27253bdea7452sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
470489cd09353a584000edaaa61558b27253bdea7452sewardj         delta += len;
470589cd09353a584000edaaa61558b27253bdea7452sewardj
470689cd09353a584000edaaa61558b27253bdea7452sewardj         switch (gregOfRM(modrm)) {
470789cd09353a584000edaaa61558b27253bdea7452sewardj
470889cd09353a584000edaaa61558b27253bdea7452sewardj            case 0: /* FILD m32int */
470989cd09353a584000edaaa61558b27253bdea7452sewardj               DIP("fildl %s\n", dis_buf);
471089cd09353a584000edaaa61558b27253bdea7452sewardj               fp_push();
47116c299f3acab617581ea504e45fbb6cab24c2b29fsewardj               put_ST(0, unop(Iop_I32StoF64,
471289cd09353a584000edaaa61558b27253bdea7452sewardj                              loadLE(Ity_I32, mkexpr(addr))));
471389cd09353a584000edaaa61558b27253bdea7452sewardj               break;
471489cd09353a584000edaaa61558b27253bdea7452sewardj
4715dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj            case 1: /* FISTTPL m32 (SSE3) */
4716dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               DIP("fisttpl %s\n", dis_buf);
4717dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               storeLE( mkexpr(addr),
47186c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) );
4719dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               fp_pop();
4720dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               break;
4721dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
47228f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj            case 2: /* FIST m32 */
472333dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fistl %s\n", dis_buf);
47248f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj               storeLE( mkexpr(addr),
47256c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
47268f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj               break;
47278f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj
472889cd09353a584000edaaa61558b27253bdea7452sewardj            case 3: /* FISTP m32 */
472933dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fistpl %s\n", dis_buf);
47308f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj               storeLE( mkexpr(addr),
47316c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
47325bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fp_pop();
473389cd09353a584000edaaa61558b27253bdea7452sewardj               break;
473417442fe8094d0f82266e5a05509f62cac8f7539esewardj
4735b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj            case 5: { /* FLD extended-real */
47367cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj               /* Uses dirty helper:
47375657923025edcb17ad6b130c3145aadabca75455sewardj                     ULong x86g_loadF80le ( UInt )
47387cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj                  addr holds the address.  First, do a dirty call to
4739b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj                  get hold of the data. */
4740c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj               IRTemp   val  = newTemp(Ity_I64);
4741c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj               IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4742c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj
47438ea867b06de73d909c29e243407713c291c8414esewardj               IRDirty* d = unsafeIRDirty_1_N (
47448ea867b06de73d909c29e243407713c291c8414esewardj                               val,
47452a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                               0/*regparms*/,
47468f40b07a47bd0fb7c6ea22dcd0e161a3ccda82ecsewardj                               "x86g_dirtyhelper_loadF80le",
47478f40b07a47bd0fb7c6ea22dcd0e161a3ccda82ecsewardj                               &x86g_dirtyhelper_loadF80le,
47488ea867b06de73d909c29e243407713c291c8414esewardj                               args
47498ea867b06de73d909c29e243407713c291c8414esewardj                            );
4750b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj               /* declare that we're reading memory */
4751b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj               d->mFx   = Ifx_Read;
475217442fe8094d0f82266e5a05509f62cac8f7539esewardj               d->mAddr = mkexpr(addr);
4753b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj               d->mSize = 10;
4754c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj
4755c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj               /* execute the dirty call, dumping the result in val. */
4756b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj               stmt( IRStmt_Dirty(d) );
4757b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj               fp_push();
4758c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj               put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4759c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj
476033dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldt %s\n", dis_buf);
476117442fe8094d0f82266e5a05509f62cac8f7539esewardj               break;
476217442fe8094d0f82266e5a05509f62cac8f7539esewardj            }
476317442fe8094d0f82266e5a05509f62cac8f7539esewardj
476417442fe8094d0f82266e5a05509f62cac8f7539esewardj            case 7: { /* FSTP extended-real */
47659fc9e782027baafd8b94163778996d6f05109f62sewardj               /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
4766c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj               IRExpr** args
4767c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj                  = mkIRExprVec_2( mkexpr(addr),
4768c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj                                   unop(Iop_ReinterpF64asI64, get_ST(0)) );
4769c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj
47708ea867b06de73d909c29e243407713c291c8414esewardj               IRDirty* d = unsafeIRDirty_0_N (
4771f96552617c82834ece36184e674e249faa899b2fsewardj                               0/*regparms*/,
47728f40b07a47bd0fb7c6ea22dcd0e161a3ccda82ecsewardj                               "x86g_dirtyhelper_storeF80le",
47738f40b07a47bd0fb7c6ea22dcd0e161a3ccda82ecsewardj                               &x86g_dirtyhelper_storeF80le,
47748ea867b06de73d909c29e243407713c291c8414esewardj                               args
47758ea867b06de73d909c29e243407713c291c8414esewardj                            );
477617442fe8094d0f82266e5a05509f62cac8f7539esewardj               /* declare we're writing memory */
477717442fe8094d0f82266e5a05509f62cac8f7539esewardj               d->mFx   = Ifx_Write;
477817442fe8094d0f82266e5a05509f62cac8f7539esewardj               d->mAddr = mkexpr(addr);
477917442fe8094d0f82266e5a05509f62cac8f7539esewardj               d->mSize = 10;
4780c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj
478117442fe8094d0f82266e5a05509f62cac8f7539esewardj               /* execute the dirty call. */
478217442fe8094d0f82266e5a05509f62cac8f7539esewardj               stmt( IRStmt_Dirty(d) );
478317442fe8094d0f82266e5a05509f62cac8f7539esewardj               fp_pop();
4784c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj
478533dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fstpt\n %s", dis_buf);
4786b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj               break;
4787b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj            }
478817442fe8094d0f82266e5a05509f62cac8f7539esewardj
4789b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj            default:
4790b173774421d015736c2316b5e6e998e7de545a5cflorian               vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
479189cd09353a584000edaaa61558b27253bdea7452sewardj               vex_printf("first_opcode == 0xDB\n");
479289cd09353a584000edaaa61558b27253bdea7452sewardj               goto decode_fail;
479389cd09353a584000edaaa61558b27253bdea7452sewardj         }
479489cd09353a584000edaaa61558b27253bdea7452sewardj
479589cd09353a584000edaaa61558b27253bdea7452sewardj      } else {
47968308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
47978308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj         delta++;
47988308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj         switch (modrm) {
47998308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
4800519d66fc0e4f16b120079bc651862e49f154da62sewardj            case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
4801519d66fc0e4f16b120079bc651862e49f154da62sewardj               r_src = (UInt)modrm - 0xC0;
4802b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fcmovnb %%st(%u), %%st(0)\n", r_src);
4803519d66fc0e4f16b120079bc651862e49f154da62sewardj               put_ST_UNCHECKED(0,
480499dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4805009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondNB),
480699dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
4807519d66fc0e4f16b120079bc651862e49f154da62sewardj               break;
4808519d66fc0e4f16b120079bc651862e49f154da62sewardj
48094e82db7b7141106436f7f543c30050f80fcc9933sewardj            case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
48104e82db7b7141106436f7f543c30050f80fcc9933sewardj               r_src = (UInt)modrm - 0xC8;
4811b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fcmovnz %%st(%u), %%st(0)\n", r_src);
48125bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               put_ST_UNCHECKED(0,
481399dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4814009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondNZ),
481599dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
48164e82db7b7141106436f7f543c30050f80fcc9933sewardj               break;
48174e82db7b7141106436f7f543c30050f80fcc9933sewardj
4818519d66fc0e4f16b120079bc651862e49f154da62sewardj            case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
4819519d66fc0e4f16b120079bc651862e49f154da62sewardj               r_src = (UInt)modrm - 0xD0;
4820b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fcmovnbe %%st(%u), %%st(0)\n", r_src);
4821519d66fc0e4f16b120079bc651862e49f154da62sewardj               put_ST_UNCHECKED(0,
482299dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4823009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondNBE),
482499dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
4825519d66fc0e4f16b120079bc651862e49f154da62sewardj               break;
4826519d66fc0e4f16b120079bc651862e49f154da62sewardj
48278253ad3c3696f46b30daf66003f7649abe70286dsewardj            case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
48288253ad3c3696f46b30daf66003f7649abe70286dsewardj               r_src = (UInt)modrm - 0xD8;
4829b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fcmovnu %%st(%u), %%st(0)\n", r_src);
48308253ad3c3696f46b30daf66003f7649abe70286dsewardj               put_ST_UNCHECKED(0,
483199dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4832009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondNP),
483399dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
48348253ad3c3696f46b30daf66003f7649abe70286dsewardj               break;
48358253ad3c3696f46b30daf66003f7649abe70286dsewardj
48367df596b1e36840e2d74c90aa55589934add61ccfsewardj            case 0xE2:
48377df596b1e36840e2d74c90aa55589934add61ccfsewardj               DIP("fnclex\n");
48387df596b1e36840e2d74c90aa55589934add61ccfsewardj               break;
48397df596b1e36840e2d74c90aa55589934add61ccfsewardj
4840a0e83b06f304527e3e9aec527c344e35e7023d76sewardj            case 0xE3: {
4841a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               /* Uses dirty helper:
4842a0e83b06f304527e3e9aec527c344e35e7023d76sewardj                     void x86g_do_FINIT ( VexGuestX86State* ) */
4843a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               IRDirty* d  = unsafeIRDirty_0_N (
4844a0e83b06f304527e3e9aec527c344e35e7023d76sewardj                                0/*regparms*/,
4845a0e83b06f304527e3e9aec527c344e35e7023d76sewardj                                "x86g_dirtyhelper_FINIT",
4846a0e83b06f304527e3e9aec527c344e35e7023d76sewardj                                &x86g_dirtyhelper_FINIT,
4847ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                                mkIRExprVec_1(IRExpr_GSPTR())
4848a0e83b06f304527e3e9aec527c344e35e7023d76sewardj                             );
4849a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4850a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               /* declare we're writing guest state */
4851a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->nFxState = 5;
4852c9069f2908814843e9a4da00da9c8905440195a6sewardj               vex_bzero(&d->fxState, sizeof(d->fxState));
4853a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4854a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[0].fx     = Ifx_Write;
4855a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[0].offset = OFFB_FTOP;
4856a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[0].size   = sizeof(UInt);
4857a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4858a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[1].fx     = Ifx_Write;
4859a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[1].offset = OFFB_FPREGS;
4860a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[1].size   = 8 * sizeof(ULong);
4861a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4862a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[2].fx     = Ifx_Write;
4863a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[2].offset = OFFB_FPTAGS;
4864a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[2].size   = 8 * sizeof(UChar);
4865a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4866a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[3].fx     = Ifx_Write;
4867a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[3].offset = OFFB_FPROUND;
4868a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[3].size   = sizeof(UInt);
4869a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4870a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[4].fx     = Ifx_Write;
4871a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[4].offset = OFFB_FC3210;
4872a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[4].size   = sizeof(UInt);
4873a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4874a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               stmt( IRStmt_Dirty(d) );
4875a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
487633dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fninit\n");
4877a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               break;
4878a0e83b06f304527e3e9aec527c344e35e7023d76sewardj            }
4879a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
48808308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
48818308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
48828308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               break;
48838308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
488437158719b222a3776df257a80c8ce44d810fae82sewardj            case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
488537158719b222a3776df257a80c8ce44d810fae82sewardj               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
488637158719b222a3776df257a80c8ce44d810fae82sewardj               break;
488737158719b222a3776df257a80c8ce44d810fae82sewardj
48888308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            default:
48898308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               goto decode_fail;
489017442fe8094d0f82266e5a05509f62cac8f7539esewardj         }
489189cd09353a584000edaaa61558b27253bdea7452sewardj      }
4892d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
4893d1725d18b61bf7912a9099686179faef5815dba1sewardj
4894d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4895d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
4896d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xDC) {
4897a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj      if (modrm < 0xC0) {
4898a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
489989cd09353a584000edaaa61558b27253bdea7452sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
4900feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            specifies an address. */
4901a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4902a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj         delta += len;
4903a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
4904a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj         switch (gregOfRM(modrm)) {
4905a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
4906a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj            case 0: /* FADD double-real */
4907a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4908a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               break;
4909a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
4910cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 1: /* FMUL double-real */
4911cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4912cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4913cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
4914e166ed089645c00ea80f732139c22ec2e2c402f1sewardj            case 2: /* FCOM double-real */
4915e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               DIP("fcoml %s\n", dis_buf);
4916e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               /* This forces C1 to zero, which isn't right. */
4917e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               put_C3210(
4918e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   binop( Iop_And32,
4919e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          binop(Iop_Shl32,
4920e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                binop(Iop_CmpF64,
4921e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                      get_ST(0),
4922e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                      loadLE(Ity_F64,mkexpr(addr))),
4923e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                mkU8(8)),
4924e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          mkU32(0x4500)
4925e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   ));
4926e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               break;
4927e166ed089645c00ea80f732139c22ec2e2c402f1sewardj
4928883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 3: /* FCOMP double-real */
4929e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               DIP("fcompl %s\n", dis_buf);
4930883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               /* This forces C1 to zero, which isn't right. */
4931883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               put_C3210(
4932883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                   binop( Iop_And32,
4933883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                          binop(Iop_Shl32,
4934883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                                binop(Iop_CmpF64,
4935883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                                      get_ST(0),
4936883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                                      loadLE(Ity_F64,mkexpr(addr))),
4937883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                                mkU8(8)),
4938883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                          mkU32(0x4500)
4939883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                   ));
4940883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               fp_pop();
4941883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               break;
4942883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
4943cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 4: /* FSUB double-real */
4944cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4945cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4946cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
49473fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 5: /* FSUBR double-real */
49483fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
49493fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
49503fd5e570294226c643f974b438225e3f09a82f4fsewardj
4951cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 6: /* FDIV double-real */
4952cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4953cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4954cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
4955883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 7: /* FDIVR double-real */
4956883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4957883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               break;
4958883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
4959a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj            default:
4960b173774421d015736c2316b5e6e998e7de545a5cflorian               vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
4961a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               vex_printf("first_opcode == 0xDC\n");
4962a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               goto decode_fail;
4963a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj         }
4964a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
4965a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj      } else {
4966bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
4967bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         delta++;
4968bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         switch (modrm) {
4969bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
49703fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
49713fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
49723fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
49733fd5e570294226c643f974b438225e3f09a82f4fsewardj
4974cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4975cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4976cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4977cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
497847341042b1b4140b5b4b42983df7bec015f7beecsewardj            case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
497947341042b1b4140b5b4b42983df7bec015f7beecsewardj               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
498047341042b1b4140b5b4b42983df7bec015f7beecsewardj               break;
498147341042b1b4140b5b4b42983df7bec015f7beecsewardj
4982cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4983cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4984cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4985cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
4986a0d48d648efc6948d5319c5b22705b397ac664b6sewardj            case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4987a0d48d648efc6948d5319c5b22705b397ac664b6sewardj               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4988a0d48d648efc6948d5319c5b22705b397ac664b6sewardj               break;
4989a0d48d648efc6948d5319c5b22705b397ac664b6sewardj
4990bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4991bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4992bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
4993bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
4994bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            default:
4995bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               goto decode_fail;
49965bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         }
4997bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
4998a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj      }
4999d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
5000d1725d18b61bf7912a9099686179faef5815dba1sewardj
5001d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5002d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
5003d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xDD) {
5004d1725d18b61bf7912a9099686179faef5815dba1sewardj
5005d1725d18b61bf7912a9099686179faef5815dba1sewardj      if (modrm < 0xC0) {
5006d1725d18b61bf7912a9099686179faef5815dba1sewardj
5007feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
5008d1725d18b61bf7912a9099686179faef5815dba1sewardj            specifies an address. */
5009bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5010bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         delta += len;
5011d1725d18b61bf7912a9099686179faef5815dba1sewardj
5012d1725d18b61bf7912a9099686179faef5815dba1sewardj         switch (gregOfRM(modrm)) {
5013d1725d18b61bf7912a9099686179faef5815dba1sewardj
5014d1725d18b61bf7912a9099686179faef5815dba1sewardj            case 0: /* FLD double-real */
501533dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldl %s\n", dis_buf);
5016207557ab2ea38239b670785c976b89d50bbb0eccsewardj               fp_push();
5017af1cecaf9c96f99381dda16f41d286fc3e4d220asewardj               put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
5018bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               break;
5019d1725d18b61bf7912a9099686179faef5815dba1sewardj
5020dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj            case 1: /* FISTTPQ m64 (SSE3) */
5021dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               DIP("fistppll %s\n", dis_buf);
5022dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               storeLE( mkexpr(addr),
50236c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI64S, mkU32(Irrm_ZERO), get_ST(0)) );
5024dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               fp_pop();
5025dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               break;
5026dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
5027d1725d18b61bf7912a9099686179faef5815dba1sewardj            case 2: /* FST double-real */
502833dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fstl %s\n", dis_buf);
50295bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               storeLE(mkexpr(addr), get_ST(0));
5030d1725d18b61bf7912a9099686179faef5815dba1sewardj               break;
503189cd09353a584000edaaa61558b27253bdea7452sewardj
5032d1725d18b61bf7912a9099686179faef5815dba1sewardj            case 3: /* FSTP double-real */
503333dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fstpl %s\n", dis_buf);
50345bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               storeLE(mkexpr(addr), get_ST(0));
50355bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fp_pop();
5036d1725d18b61bf7912a9099686179faef5815dba1sewardj               break;
5037d1725d18b61bf7912a9099686179faef5815dba1sewardj
50389fc9e782027baafd8b94163778996d6f05109f62sewardj            case 4: { /* FRSTOR m108 */
5039893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               /* Uses dirty helper:
50406ef84bed9bb3af22060eb1759788034602bbcc88florian                     VexEmNote x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
5041893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               IRTemp   ew = newTemp(Ity_I32);
5042893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               IRDirty* d  = unsafeIRDirty_0_N (
5043893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                                0/*regparms*/,
5044893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                                "x86g_dirtyhelper_FRSTOR",
5045893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                                &x86g_dirtyhelper_FRSTOR,
5046ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                                mkIRExprVec_2( IRExpr_GSPTR(), mkexpr(addr) )
5047893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                             );
504874142b8c8d5d3b3db17d744f5d5fb80f548bcf74sewardj               d->tmp   = ew;
50499fc9e782027baafd8b94163778996d6f05109f62sewardj               /* declare we're reading memory */
50509fc9e782027baafd8b94163778996d6f05109f62sewardj               d->mFx   = Ifx_Read;
50519fc9e782027baafd8b94163778996d6f05109f62sewardj               d->mAddr = mkexpr(addr);
50529fc9e782027baafd8b94163778996d6f05109f62sewardj               d->mSize = 108;
50539fc9e782027baafd8b94163778996d6f05109f62sewardj
50549fc9e782027baafd8b94163778996d6f05109f62sewardj               /* declare we're writing guest state */
5055893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               d->nFxState = 5;
5056c9069f2908814843e9a4da00da9c8905440195a6sewardj               vex_bzero(&d->fxState, sizeof(d->fxState));
50579fc9e782027baafd8b94163778996d6f05109f62sewardj
50589fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[0].fx     = Ifx_Write;
5059c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[0].offset = OFFB_FTOP;
50609fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[0].size   = sizeof(UInt);
50619fc9e782027baafd8b94163778996d6f05109f62sewardj
50629fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[1].fx     = Ifx_Write;
5063c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[1].offset = OFFB_FPREGS;
50649fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[1].size   = 8 * sizeof(ULong);
50659fc9e782027baafd8b94163778996d6f05109f62sewardj
50669fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[2].fx     = Ifx_Write;
5067c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[2].offset = OFFB_FPTAGS;
50689fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[2].size   = 8 * sizeof(UChar);
50699fc9e782027baafd8b94163778996d6f05109f62sewardj
50709fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[3].fx     = Ifx_Write;
5071c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[3].offset = OFFB_FPROUND;
50729fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[3].size   = sizeof(UInt);
50739fc9e782027baafd8b94163778996d6f05109f62sewardj
50749fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[4].fx     = Ifx_Write;
5075c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[4].offset = OFFB_FC3210;
50769fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[4].size   = sizeof(UInt);
50779fc9e782027baafd8b94163778996d6f05109f62sewardj
50789fc9e782027baafd8b94163778996d6f05109f62sewardj               stmt( IRStmt_Dirty(d) );
50799fc9e782027baafd8b94163778996d6f05109f62sewardj
5080893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               /* ew contains any emulation warning we may need to
5081893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  issue.  If needed, side-exit to the next insn,
5082893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  reporting the warning, so that Valgrind's dispatcher
5083893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  sees the warning. */
5084893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               put_emwarn( mkexpr(ew) );
5085893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               stmt(
5086893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  IRStmt_Exit(
5087893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5088893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                     Ijk_EmWarn,
5089c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
5090c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     OFFB_EIP
5091893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  )
5092893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               );
5093893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj
509433dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("frstor %s\n", dis_buf);
50959fc9e782027baafd8b94163778996d6f05109f62sewardj               break;
50969fc9e782027baafd8b94163778996d6f05109f62sewardj            }
50979fc9e782027baafd8b94163778996d6f05109f62sewardj
50989fc9e782027baafd8b94163778996d6f05109f62sewardj            case 6: { /* FNSAVE m108 */
5099893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               /* Uses dirty helper:
5100893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                     void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
51019fc9e782027baafd8b94163778996d6f05109f62sewardj               IRDirty* d = unsafeIRDirty_0_N (
51029fc9e782027baafd8b94163778996d6f05109f62sewardj                               0/*regparms*/,
51039fc9e782027baafd8b94163778996d6f05109f62sewardj                               "x86g_dirtyhelper_FSAVE",
51049fc9e782027baafd8b94163778996d6f05109f62sewardj                               &x86g_dirtyhelper_FSAVE,
5105ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                               mkIRExprVec_2( IRExpr_GSPTR(), mkexpr(addr) )
51069fc9e782027baafd8b94163778996d6f05109f62sewardj                            );
51079fc9e782027baafd8b94163778996d6f05109f62sewardj               /* declare we're writing memory */
51089fc9e782027baafd8b94163778996d6f05109f62sewardj               d->mFx   = Ifx_Write;
51099fc9e782027baafd8b94163778996d6f05109f62sewardj               d->mAddr = mkexpr(addr);
51109fc9e782027baafd8b94163778996d6f05109f62sewardj               d->mSize = 108;
51119fc9e782027baafd8b94163778996d6f05109f62sewardj
51129fc9e782027baafd8b94163778996d6f05109f62sewardj               /* declare we're reading guest state */
5113893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               d->nFxState = 5;
5114c9069f2908814843e9a4da00da9c8905440195a6sewardj               vex_bzero(&d->fxState, sizeof(d->fxState));
51159fc9e782027baafd8b94163778996d6f05109f62sewardj
51169fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[0].fx     = Ifx_Read;
5117c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[0].offset = OFFB_FTOP;
51189fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[0].size   = sizeof(UInt);
51199fc9e782027baafd8b94163778996d6f05109f62sewardj
51209fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[1].fx     = Ifx_Read;
5121c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[1].offset = OFFB_FPREGS;
51229fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[1].size   = 8 * sizeof(ULong);
51239fc9e782027baafd8b94163778996d6f05109f62sewardj
51249fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[2].fx     = Ifx_Read;
5125c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[2].offset = OFFB_FPTAGS;
51269fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[2].size   = 8 * sizeof(UChar);
51279fc9e782027baafd8b94163778996d6f05109f62sewardj
51289fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[3].fx     = Ifx_Read;
5129c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[3].offset = OFFB_FPROUND;
51309fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[3].size   = sizeof(UInt);
51319fc9e782027baafd8b94163778996d6f05109f62sewardj
51329fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[4].fx     = Ifx_Read;
5133c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[4].offset = OFFB_FC3210;
51349fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[4].size   = sizeof(UInt);
51359fc9e782027baafd8b94163778996d6f05109f62sewardj
51369fc9e782027baafd8b94163778996d6f05109f62sewardj               stmt( IRStmt_Dirty(d) );
51379fc9e782027baafd8b94163778996d6f05109f62sewardj
513833dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fnsave %s\n", dis_buf);
51399fc9e782027baafd8b94163778996d6f05109f62sewardj               break;
51409fc9e782027baafd8b94163778996d6f05109f62sewardj            }
51419fc9e782027baafd8b94163778996d6f05109f62sewardj
5142d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj            case 7: { /* FNSTSW m16 */
5143d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj               IRExpr* sw = get_FPU_sw();
5144dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj               vassert(typeOfIRExpr(irsb->tyenv, sw) == Ity_I16);
5145d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj               storeLE( mkexpr(addr), sw );
5146d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj               DIP("fnstsw %s\n", dis_buf);
5147d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj               break;
5148d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj            }
5149d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj
5150d1725d18b61bf7912a9099686179faef5815dba1sewardj            default:
5151b173774421d015736c2316b5e6e998e7de545a5cflorian               vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
5152bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               vex_printf("first_opcode == 0xDD\n");
5153d1725d18b61bf7912a9099686179faef5815dba1sewardj               goto decode_fail;
5154bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         }
5155d1725d18b61bf7912a9099686179faef5815dba1sewardj      } else {
5156a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj         delta++;
5157a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj         switch (modrm) {
5158bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
51593ddedc40adb12bef9a56e872c9f561ae49a9109esewardj            case 0xC0 ... 0xC7: /* FFREE %st(?) */
51603ddedc40adb12bef9a56e872c9f561ae49a9109esewardj               r_dst = (UInt)modrm - 0xC0;
5161b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("ffree %%st(%u)\n", r_dst);
51623ddedc40adb12bef9a56e872c9f561ae49a9109esewardj               put_ST_TAG ( r_dst, mkU8(0) );
51633ddedc40adb12bef9a56e872c9f561ae49a9109esewardj               break;
51643ddedc40adb12bef9a56e872c9f561ae49a9109esewardj
516506c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj            case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
516606c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               r_dst = (UInt)modrm - 0xD0;
5167b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fst %%st(0),%%st(%u)\n", r_dst);
51685bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               /* P4 manual says: "If the destination operand is a
516906c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj                  non-empty register, the invalid-operation exception
517006c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj                  is not generated.  Hence put_ST_UNCHECKED. */
517106c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               put_ST_UNCHECKED(r_dst, get_ST(0));
517206c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               break;
517306c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj
5174a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj            case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5175a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               r_dst = (UInt)modrm - 0xD8;
5176b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fstp %%st(0),%%st(%u)\n", r_dst);
51775bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               /* P4 manual says: "If the destination operand is a
5178207557ab2ea38239b670785c976b89d50bbb0eccsewardj                  non-empty register, the invalid-operation exception
5179207557ab2ea38239b670785c976b89d50bbb0eccsewardj                  is not generated.  Hence put_ST_UNCHECKED. */
5180207557ab2ea38239b670785c976b89d50bbb0eccsewardj               put_ST_UNCHECKED(r_dst, get_ST(0));
5181207557ab2ea38239b670785c976b89d50bbb0eccsewardj               fp_pop();
5182a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               break;
5183bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5184bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5185bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               r_dst = (UInt)modrm - 0xE0;
5186b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fucom %%st(0),%%st(%u)\n", r_dst);
5187c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               /* This forces C1 to zero, which isn't right. */
5188c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               put_C3210(
5189c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                   binop( Iop_And32,
5190c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                          binop(Iop_Shl32,
5191c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5192c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                                mkU8(8)),
5193c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                          mkU32(0x4500)
5194c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                   ));
5195bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
5196bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5197bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5198bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               r_dst = (UInt)modrm - 0xE8;
5199b173774421d015736c2316b5e6e998e7de545a5cflorian               DIP("fucomp %%st(0),%%st(%u)\n", r_dst);
5200c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               /* This forces C1 to zero, which isn't right. */
5201c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               put_C3210(
5202c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                   binop( Iop_And32,
5203c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                          binop(Iop_Shl32,
5204c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5205c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                                mkU8(8)),
5206c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                          mkU32(0x4500)
5207c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                   ));
5208bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_pop();
5209bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
5210bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
52115bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            default:
5212a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               goto decode_fail;
52135bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         }
5214d1725d18b61bf7912a9099686179faef5815dba1sewardj      }
5215d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
5216d1725d18b61bf7912a9099686179faef5815dba1sewardj
5217d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5218d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
5219d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xDE) {
5220bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5221bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      if (modrm < 0xC0) {
5222feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5223feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
5224feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            specifies an address. */
5225feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         IROp   fop;
5226feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5227feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         delta += len;
5228feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5229feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         switch (gregOfRM(modrm)) {
5230feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5231feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 0: /* FIADD m16int */ /* ST(0) += m16int */
523233dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fiaddw %s\n", dis_buf);
5233feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fop = Iop_AddF64;
5234feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto do_fop_m16;
5235feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5236feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
523733dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fimulw %s\n", dis_buf);
5238feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fop = Iop_MulF64;
5239feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto do_fop_m16;
5240feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5241071895fca57b5b710485a4951fef12317e337064sewardj            case 2: /* FICOM m16int */
5242071895fca57b5b710485a4951fef12317e337064sewardj               DIP("ficomw %s\n", dis_buf);
5243071895fca57b5b710485a4951fef12317e337064sewardj               /* This forces C1 to zero, which isn't right. */
5244071895fca57b5b710485a4951fef12317e337064sewardj               put_C3210(
5245071895fca57b5b710485a4951fef12317e337064sewardj                   binop( Iop_And32,
5246071895fca57b5b710485a4951fef12317e337064sewardj                          binop(Iop_Shl32,
5247071895fca57b5b710485a4951fef12317e337064sewardj                                binop(Iop_CmpF64,
5248071895fca57b5b710485a4951fef12317e337064sewardj                                      get_ST(0),
52496c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                                      unop(Iop_I32StoF64,
5250071895fca57b5b710485a4951fef12317e337064sewardj                                         unop(Iop_16Sto32,
5251071895fca57b5b710485a4951fef12317e337064sewardj                                           loadLE(Ity_I16,mkexpr(addr))))),
5252071895fca57b5b710485a4951fef12317e337064sewardj                                mkU8(8)),
5253071895fca57b5b710485a4951fef12317e337064sewardj                          mkU32(0x4500)
5254071895fca57b5b710485a4951fef12317e337064sewardj                   ));
5255071895fca57b5b710485a4951fef12317e337064sewardj               break;
5256071895fca57b5b710485a4951fef12317e337064sewardj
5257071895fca57b5b710485a4951fef12317e337064sewardj            case 3: /* FICOMP m16int */
5258071895fca57b5b710485a4951fef12317e337064sewardj               DIP("ficompw %s\n", dis_buf);
5259071895fca57b5b710485a4951fef12317e337064sewardj               /* This forces C1 to zero, which isn't right. */
5260071895fca57b5b710485a4951fef12317e337064sewardj               put_C3210(
5261071895fca57b5b710485a4951fef12317e337064sewardj                   binop( Iop_And32,
5262071895fca57b5b710485a4951fef12317e337064sewardj                          binop(Iop_Shl32,
5263071895fca57b5b710485a4951fef12317e337064sewardj                                binop(Iop_CmpF64,
5264071895fca57b5b710485a4951fef12317e337064sewardj                                      get_ST(0),
52656c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                                      unop(Iop_I32StoF64,
5266071895fca57b5b710485a4951fef12317e337064sewardj                                         unop(Iop_16Sto32,
5267f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                                              loadLE(Ity_I16,mkexpr(addr))))),
5268071895fca57b5b710485a4951fef12317e337064sewardj                                mkU8(8)),
5269071895fca57b5b710485a4951fef12317e337064sewardj                          mkU32(0x4500)
5270071895fca57b5b710485a4951fef12317e337064sewardj                   ));
5271071895fca57b5b710485a4951fef12317e337064sewardj               fp_pop();
5272071895fca57b5b710485a4951fef12317e337064sewardj               break;
5273071895fca57b5b710485a4951fef12317e337064sewardj
5274feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 4: /* FISUB m16int */ /* ST(0) -= m16int */
527533dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fisubw %s\n", dis_buf);
5276feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fop = Iop_SubF64;
5277feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto do_fop_m16;
5278feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5279feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
528033dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fisubrw %s\n", dis_buf);
5281feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fop = Iop_SubF64;
5282feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto do_foprev_m16;
5283feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5284feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
528533dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fisubw %s\n", dis_buf);
5286feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fop = Iop_DivF64;
5287feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto do_fop_m16;
5288feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5289feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
529033dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fidivrw %s\n", dis_buf);
5291feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fop = Iop_DivF64;
5292feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto do_foprev_m16;
5293feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5294feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            do_fop_m16:
5295feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               put_ST_UNCHECKED(0,
5296f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(fop,
5297f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5298feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj                        get_ST(0),
52996c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        unop(Iop_I32StoF64,
5300feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj                             unop(Iop_16Sto32,
5301feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj                                  loadLE(Ity_I16, mkexpr(addr))))));
5302feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               break;
5303feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5304feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            do_foprev_m16:
5305feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               put_ST_UNCHECKED(0,
5306f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(fop,
5307f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
53086c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        unop(Iop_I32StoF64,
5309feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj                             unop(Iop_16Sto32,
5310feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj                                  loadLE(Ity_I16, mkexpr(addr)))),
5311feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj                        get_ST(0)));
5312feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               break;
5313feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5314feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            default:
5315b173774421d015736c2316b5e6e998e7de545a5cflorian               vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
5316feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               vex_printf("first_opcode == 0xDE\n");
5317feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto decode_fail;
5318feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         }
5319bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5320bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      } else {
5321bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5322bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         delta++;
53235bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         switch (modrm) {
5324bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5325cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5326cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5327cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
5328cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
5329bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5330bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5331bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
5332bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5333e166ed089645c00ea80f732139c22ec2e2c402f1sewardj            case 0xD9: /* FCOMPP %st(0),%st(1) */
5334e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               DIP("fuompp %%st(0),%%st(1)\n");
5335e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               /* This forces C1 to zero, which isn't right. */
5336e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               put_C3210(
5337e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   binop( Iop_And32,
5338e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          binop(Iop_Shl32,
5339e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5340e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                mkU8(8)),
5341e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          mkU32(0x4500)
5342e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   ));
5343e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               fp_pop();
5344e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               fp_pop();
5345e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               break;
5346e166ed089645c00ea80f732139c22ec2e2c402f1sewardj
5347cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5348cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0,  modrm - 0xE0, True );
5349cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
5350cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
53513fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
53523fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_op_ST_ST ( "sub", Iop_SubF64, 0,  modrm - 0xE8, True );
53533fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
53543fd5e570294226c643f974b438225e3f09a82f4fsewardj
5355bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5356bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5357bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
5358bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5359bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5360bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5361bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
5362bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5363bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            default:
5364bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               goto decode_fail;
53655bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         }
5366bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5367bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      }
5368d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
5369d1725d18b61bf7912a9099686179faef5815dba1sewardj
5370d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5371d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
5372d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xDF) {
537389cd09353a584000edaaa61558b27253bdea7452sewardj
537489cd09353a584000edaaa61558b27253bdea7452sewardj      if (modrm < 0xC0) {
537589cd09353a584000edaaa61558b27253bdea7452sewardj
5376feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
537789cd09353a584000edaaa61558b27253bdea7452sewardj            specifies an address. */
537889cd09353a584000edaaa61558b27253bdea7452sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
537989cd09353a584000edaaa61558b27253bdea7452sewardj         delta += len;
538089cd09353a584000edaaa61558b27253bdea7452sewardj
538189cd09353a584000edaaa61558b27253bdea7452sewardj         switch (gregOfRM(modrm)) {
538289cd09353a584000edaaa61558b27253bdea7452sewardj
5383883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 0: /* FILD m16int */
5384883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               DIP("fildw %s\n", dis_buf);
5385883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               fp_push();
53866c299f3acab617581ea504e45fbb6cab24c2b29fsewardj               put_ST(0, unop(Iop_I32StoF64,
5387883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                              unop(Iop_16Sto32,
5388883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                                   loadLE(Ity_I16, mkexpr(addr)))));
5389883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               break;
5390883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
5391dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj            case 1: /* FISTTPS m16 (SSE3) */
5392dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               DIP("fisttps %s\n", dis_buf);
5393dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               storeLE( mkexpr(addr),
53946c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI16S, mkU32(Irrm_ZERO), get_ST(0)) );
5395dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               fp_pop();
5396dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               break;
5397dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
539837158719b222a3776df257a80c8ce44d810fae82sewardj            case 2: /* FIST m16 */
539933dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fistp %s\n", dis_buf);
540037158719b222a3776df257a80c8ce44d810fae82sewardj               storeLE( mkexpr(addr),
54016c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
540237158719b222a3776df257a80c8ce44d810fae82sewardj               break;
540337158719b222a3776df257a80c8ce44d810fae82sewardj
540489cd09353a584000edaaa61558b27253bdea7452sewardj            case 3: /* FISTP m16 */
540533dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fistps %s\n", dis_buf);
54068f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj               storeLE( mkexpr(addr),
54076c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
54088f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj               fp_pop();
540989cd09353a584000edaaa61558b27253bdea7452sewardj               break;
541089cd09353a584000edaaa61558b27253bdea7452sewardj
541189cd09353a584000edaaa61558b27253bdea7452sewardj            case 5: /* FILD m64 */
541289cd09353a584000edaaa61558b27253bdea7452sewardj               DIP("fildll %s\n", dis_buf);
541389cd09353a584000edaaa61558b27253bdea7452sewardj               fp_push();
54146c299f3acab617581ea504e45fbb6cab24c2b29fsewardj               put_ST(0, binop(Iop_I64StoF64,
54154cb918d355cef4e7640d374346852db4556f3524sewardj                               get_roundingmode(),
54164cb918d355cef4e7640d374346852db4556f3524sewardj                               loadLE(Ity_I64, mkexpr(addr))));
541789cd09353a584000edaaa61558b27253bdea7452sewardj               break;
541889cd09353a584000edaaa61558b27253bdea7452sewardj
5419cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 7: /* FISTP m64 */
542033dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fistpll %s\n", dis_buf);
5421cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               storeLE( mkexpr(addr),
54226c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI64S, get_roundingmode(), get_ST(0)) );
5423cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_pop();
5424cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
5425cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
542689cd09353a584000edaaa61558b27253bdea7452sewardj            default:
5427b173774421d015736c2316b5e6e998e7de545a5cflorian               vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
542889cd09353a584000edaaa61558b27253bdea7452sewardj               vex_printf("first_opcode == 0xDF\n");
542989cd09353a584000edaaa61558b27253bdea7452sewardj               goto decode_fail;
543089cd09353a584000edaaa61558b27253bdea7452sewardj         }
543189cd09353a584000edaaa61558b27253bdea7452sewardj
543289cd09353a584000edaaa61558b27253bdea7452sewardj      } else {
5433bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5434bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         delta++;
54355bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         switch (modrm) {
5436bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
54378fb88693f03ab70a8122094933fe7fa3ae907bfbsewardj            case 0xC0: /* FFREEP %st(0) */
54388fb88693f03ab70a8122094933fe7fa3ae907bfbsewardj               DIP("ffreep %%st(%d)\n", 0);
54398fb88693f03ab70a8122094933fe7fa3ae907bfbsewardj               put_ST_TAG ( 0, mkU8(0) );
54408fb88693f03ab70a8122094933fe7fa3ae907bfbsewardj               fp_pop();
54418fb88693f03ab70a8122094933fe7fa3ae907bfbsewardj               break;
54428fb88693f03ab70a8122094933fe7fa3ae907bfbsewardj
5443bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xE0: /* FNSTSW %ax */
5444bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               DIP("fnstsw %%ax\n");
5445d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj               /* Get the FPU status word value and dump it in %AX. */
54461d2e77f4c2a59424eedbb257040d399022bab7a8sewardj               if (0) {
54471d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  /* The obvious thing to do is simply dump the 16-bit
54481d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     status word value in %AX.  However, due to a
54491d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     limitation in Memcheck's origin tracking
54501d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     machinery, this causes Memcheck not to track the
54511d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     origin of any undefinedness into %AH (only into
54521d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     %AL/%AX/%EAX), which means origins are lost in
54531d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     the sequence "fnstsw %ax; test $M,%ah; jcond .." */
54541d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  putIReg(2, R_EAX, get_FPU_sw());
54551d2e77f4c2a59424eedbb257040d399022bab7a8sewardj               } else {
54561d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  /* So a somewhat lame kludge is to make it very
54571d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     clear to Memcheck that the value is written to
54581d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     both %AH and %AL.  This generates marginally
54591d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     worse code, but I don't think it matters much. */
54601d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  IRTemp t16 = newTemp(Ity_I16);
54611d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  assign(t16, get_FPU_sw());
54621d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  putIReg( 1, R_AL, unop(Iop_16to8, mkexpr(t16)) );
54631d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  putIReg( 1, R_AH, unop(Iop_16HIto8, mkexpr(t16)) );
54641d2e77f4c2a59424eedbb257040d399022bab7a8sewardj               }
5465bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
5466bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5467883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
54688308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
5469883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               break;
5470883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
5471feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5472feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               /* not really right since COMIP != UCOMIP */
5473feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5474feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               break;
5475feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5476bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            default:
5477bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               goto decode_fail;
54785bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         }
547989cd09353a584000edaaa61558b27253bdea7452sewardj      }
548089cd09353a584000edaaa61558b27253bdea7452sewardj
5481d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
5482d1725d18b61bf7912a9099686179faef5815dba1sewardj
5483d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
5484d1725d18b61bf7912a9099686179faef5815dba1sewardj   vpanic("dis_FPU(x86): invalid primary opcode");
5485d1725d18b61bf7912a9099686179faef5815dba1sewardj
548669d9d664b76ef1c8a6b75917161d44c525556a19sewardj   *decode_ok = True;
548769d9d664b76ef1c8a6b75917161d44c525556a19sewardj   return delta;
548869d9d664b76ef1c8a6b75917161d44c525556a19sewardj
5489d1725d18b61bf7912a9099686179faef5815dba1sewardj  decode_fail:
5490d1725d18b61bf7912a9099686179faef5815dba1sewardj   *decode_ok = False;
5491d1725d18b61bf7912a9099686179faef5815dba1sewardj   return delta;
5492d1725d18b61bf7912a9099686179faef5815dba1sewardj}
5493d1725d18b61bf7912a9099686179faef5815dba1sewardj
5494d1725d18b61bf7912a9099686179faef5815dba1sewardj
5495464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*------------------------------------------------------------*/
5496464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*---                                                      ---*/
5497464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*--- MMX INSTRUCTIONS                                     ---*/
5498464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*---                                                      ---*/
5499464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*------------------------------------------------------------*/
5500464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5501464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/* Effect of MMX insns on x87 FPU state (table 11-2 of
5502464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   IA32 arch manual, volume 3):
5503464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5504464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   Read from, or write to MMX register (viz, any insn except EMMS):
5505464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5506464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   * FP stack pointer set to zero
5507464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5508464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   EMMS:
5509464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5510464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   * FP stack pointer set to zero
5511464efa446b2db97115d3e5f04af5db3464cc0e93sewardj*/
5512464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
55134cb918d355cef4e7640d374346852db4556f3524sewardjstatic void do_MMX_preamble ( void )
5514464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
5515dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   Int         i;
5516dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5517dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRExpr*     zero  = mkU32(0);
5518dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRExpr*     tag1  = mkU8(1);
5519464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   put_ftop(zero);
5520464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   for (i = 0; i < 8; i++)
5521d6f38b3f822f7d57adfc0da3410995d85d6a4597florian      stmt( IRStmt_PutI( mkIRPutI(descr, zero, i, tag1) ) );
5522464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
5523464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
55244cb918d355cef4e7640d374346852db4556f3524sewardjstatic void do_EMMS_preamble ( void )
5525464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
5526dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   Int         i;
5527dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5528dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRExpr*     zero  = mkU32(0);
5529dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRExpr*     tag0  = mkU8(0);
5530464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   put_ftop(zero);
5531464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   for (i = 0; i < 8; i++)
5532d6f38b3f822f7d57adfc0da3410995d85d6a4597florian      stmt( IRStmt_PutI( mkIRPutI(descr, zero, i, tag0) ) );
5533464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
5534464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5535464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5536464efa446b2db97115d3e5f04af5db3464cc0e93sewardjstatic IRExpr* getMMXReg ( UInt archreg )
5537464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
5538464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   vassert(archreg < 8);
5539464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5540464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
5541464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5542464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5543464efa446b2db97115d3e5f04af5db3464cc0e93sewardjstatic void putMMXReg ( UInt archreg, IRExpr* e )
5544464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
5545464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   vassert(archreg < 8);
5546dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
5547464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5548464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
5549464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5550464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
555138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj/* Helper for non-shift MMX insns.  Note this is incomplete in the
555238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   sense that it does not first call do_MMX_preamble() -- that is the
555338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   responsibility of its caller. */
555438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
5555464efa446b2db97115d3e5f04af5db3464cc0e93sewardjstatic
55562d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardjUInt dis_MMXop_regmem_to_reg ( UChar  sorb,
555752d049186d07991237a825ec88aa7f1f303edb70sewardj                               Int    delta,
55582d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj                               UChar  opc,
555955085f8680acc89d727e321f3b34cae1a8c4093aflorian                               const HChar* name,
55602d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj                               Bool   show_granularity )
5561464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
5562c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar   dis_buf[50];
556363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   UChar   modrm = getIByte(delta);
556463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   Bool    isReg = epartIsReg(modrm);
556563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   IRExpr* argL  = NULL;
556663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   IRExpr* argR  = NULL;
556738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRExpr* argG  = NULL;
556838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRExpr* argE  = NULL;
556963ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   IRTemp  res   = newTemp(Ity_I64);
5570464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
557138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   Bool    invG  = False;
557238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IROp    op    = Iop_INVALID;
557338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   void*   hAddr = NULL;
557438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   Bool    eLeft = False;
557555085f8680acc89d727e321f3b34cae1a8c4093aflorian   const HChar*  hName = NULL;
557638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
55772b7a9208ee96939f12896085a143891160dc539asewardj#  define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
5578464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5579464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   switch (opc) {
5580b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      /* Original MMX ones */
558138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xFC: op = Iop_Add8x8; break;
558238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xFD: op = Iop_Add16x4; break;
558338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xFE: op = Iop_Add32x2; break;
5584464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
558538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xEC: op = Iop_QAdd8Sx8; break;
558638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xED: op = Iop_QAdd16Sx4; break;
5587464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
558838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xDC: op = Iop_QAdd8Ux8; break;
558938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xDD: op = Iop_QAdd16Ux4; break;
5590464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
559138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF8: op = Iop_Sub8x8;  break;
559238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF9: op = Iop_Sub16x4; break;
559338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xFA: op = Iop_Sub32x2; break;
55944340dac5c2cede4962868e6da5b73282da2bc465sewardj
559538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE8: op = Iop_QSub8Sx8; break;
559638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE9: op = Iop_QSub16Sx4; break;
55974340dac5c2cede4962868e6da5b73282da2bc465sewardj
559838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD8: op = Iop_QSub8Ux8; break;
559938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD9: op = Iop_QSub16Ux4; break;
560063ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
560138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE5: op = Iop_MulHi16Sx4; break;
560238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD5: op = Iop_Mul16x4; break;
560338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
560463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
560538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x74: op = Iop_CmpEQ8x8; break;
560638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x75: op = Iop_CmpEQ16x4; break;
560738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x76: op = Iop_CmpEQ32x2; break;
560863ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
560938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x64: op = Iop_CmpGT8Sx8; break;
561038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x65: op = Iop_CmpGT16Sx4; break;
561138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x66: op = Iop_CmpGT32Sx2; break;
561263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
56135f438dd73072211989c6d496845bdc9b777ecbecsewardj      case 0x6B: op = Iop_QNarrowBin32Sto16Sx4; eLeft = True; break;
56145f438dd73072211989c6d496845bdc9b777ecbecsewardj      case 0x63: op = Iop_QNarrowBin16Sto8Sx8;  eLeft = True; break;
56155f438dd73072211989c6d496845bdc9b777ecbecsewardj      case 0x67: op = Iop_QNarrowBin16Sto8Ux8;  eLeft = True; break;
56168d14a59858e2464baa217f19daff83562f3cdca0sewardj
561738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x68: op = Iop_InterleaveHI8x8;  eLeft = True; break;
561838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
561938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
56208d14a59858e2464baa217f19daff83562f3cdca0sewardj
562138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x60: op = Iop_InterleaveLO8x8;  eLeft = True; break;
562238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
562338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
56248d14a59858e2464baa217f19daff83562f3cdca0sewardj
562538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xDB: op = Iop_And64; break;
562638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xDF: op = Iop_And64; invG = True; break;
562738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xEB: op = Iop_Or64; break;
562838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xEF: /* Possibly do better here if argL and argR are the
562938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                    same reg */
563038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 op = Iop_Xor64; break;
5631464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5632b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      /* Introduced in SSE1 */
563338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE0: op = Iop_Avg8Ux8;    break;
563438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE3: op = Iop_Avg16Ux4;   break;
563538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xEE: op = Iop_Max16Sx4;   break;
563638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xDE: op = Iop_Max8Ux8;    break;
563738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xEA: op = Iop_Min16Sx4;   break;
563838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xDA: op = Iop_Min8Ux8;    break;
563938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE4: op = Iop_MulHi16Ux4; break;
564038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
5641b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
5642164f9275c465cd09ecd09276b8542282f5def250sewardj      /* Introduced in SSE2 */
564338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD4: op = Iop_Add64; break;
564438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xFB: op = Iop_Sub64; break;
5645164f9275c465cd09ecd09276b8542282f5def250sewardj
5646464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      default:
5647b173774421d015736c2316b5e6e998e7de545a5cflorian         vex_printf("\n0x%x\n", opc);
5648464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         vpanic("dis_MMXop_regmem_to_reg");
5649464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   }
5650464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5651464efa446b2db97115d3e5f04af5db3464cc0e93sewardj#  undef XXX
5652464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
565338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   argG = getMMXReg(gregOfRM(modrm));
565438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (invG)
565538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argG = unop(Iop_Not64, argG);
565663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
5657464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   if (isReg) {
5658464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      delta++;
565938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argE = getMMXReg(eregOfRM(modrm));
5660464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   } else {
5661464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      Int    len;
5662464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5663464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      delta += len;
566438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argE = loadLE(Ity_I64, mkexpr(addr));
566563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   }
566663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
566738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (eLeft) {
566838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argL = argE;
566938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argR = argG;
567038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else {
567138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argL = argG;
567238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argR = argE;
567338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   }
567438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
567538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (op != Iop_INVALID) {
567638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      vassert(hName == NULL);
567738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      vassert(hAddr == NULL);
567838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      assign(res, binop(op, argL, argR));
567938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else {
568038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      vassert(hName != NULL);
568138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      vassert(hAddr != NULL);
568238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      assign( res,
568338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj              mkIRExprCCall(
568438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 Ity_I64,
568538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 0/*regparms*/, hName, hAddr,
568638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 mkIRExprVec_2( argL, argR )
568738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj              )
568838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj            );
5689464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   }
5690464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
569163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   putMMXReg( gregOfRM(modrm), mkexpr(res) );
569263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
5693464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   DIP("%s%s %s, %s\n",
56942d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj       name, show_granularity ? nameMMXGran(opc & 3) : "",
5695464efa446b2db97115d3e5f04af5db3464cc0e93sewardj       ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5696464efa446b2db97115d3e5f04af5db3464cc0e93sewardj       nameMMXReg(gregOfRM(modrm)) );
5697464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5698464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   return delta;
5699464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
5700464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5701464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
570238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj/* Vector by scalar shift of G by the amount specified at the bottom
570338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   of E.  This is a straight copy of dis_SSE_shiftG_byE. */
570438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
570552d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt dis_MMX_shiftG_byE ( UChar sorb, Int delta,
570655085f8680acc89d727e321f3b34cae1a8c4093aflorian                                 const HChar* opname, IROp op )
570738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj{
570838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   HChar   dis_buf[50];
570938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   Int     alen, size;
571038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  addr;
571138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   Bool    shl, shr, sar;
571238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   UChar   rm   = getIByte(delta);
571338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  g0   = newTemp(Ity_I64);
571438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  g1   = newTemp(Ity_I64);
571538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  amt  = newTemp(Ity_I32);
571638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  amt8 = newTemp(Ity_I8);
571738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
571838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (epartIsReg(rm)) {
571938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
572038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      DIP("%s %s,%s\n", opname,
572138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                        nameMMXReg(eregOfRM(rm)),
572238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                        nameMMXReg(gregOfRM(rm)) );
572338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta++;
572438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else {
572538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
572638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
572738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      DIP("%s %s,%s\n", opname,
572838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                        dis_buf,
572938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                        nameMMXReg(gregOfRM(rm)) );
573038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta += alen;
573138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   }
573238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   assign( g0,   getMMXReg(gregOfRM(rm)) );
573338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
573438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
573538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   shl = shr = sar = False;
573638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   size = 0;
573738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   switch (op) {
573838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShlN16x4: shl = True; size = 32; break;
573938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShlN32x2: shl = True; size = 32; break;
574038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_Shl64:    shl = True; size = 64; break;
574138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShrN16x4: shr = True; size = 16; break;
574238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShrN32x2: shr = True; size = 32; break;
574338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_Shr64:    shr = True; size = 64; break;
574438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_SarN16x4: sar = True; size = 16; break;
574538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_SarN32x2: sar = True; size = 32; break;
574638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      default: vassert(0);
574738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   }
574838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
574938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (shl || shr) {
575038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj     assign(
575138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj        g1,
575299dd03e04a6914d90d5fee727d61d76905334becflorian        IRExpr_ITE(
5753009230b9758291b594e60d7c0243a73d53e81854sewardj           binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
575499dd03e04a6914d90d5fee727d61d76905334becflorian           binop(op, mkexpr(g0), mkexpr(amt8)),
575599dd03e04a6914d90d5fee727d61d76905334becflorian           mkU64(0)
575638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj        )
575738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj     );
575838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else
575938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (sar) {
576038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj     assign(
576138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj        g1,
576299dd03e04a6914d90d5fee727d61d76905334becflorian        IRExpr_ITE(
5763009230b9758291b594e60d7c0243a73d53e81854sewardj           binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
576499dd03e04a6914d90d5fee727d61d76905334becflorian           binop(op, mkexpr(g0), mkexpr(amt8)),
576599dd03e04a6914d90d5fee727d61d76905334becflorian           binop(op, mkexpr(g0), mkU8(size-1))
576638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj        )
576738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj     );
576838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else {
5769ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      /*NOTREACHED*/
577038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      vassert(0);
577138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   }
577238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
577338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   putMMXReg( gregOfRM(rm), mkexpr(g1) );
577438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   return delta;
577538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj}
577638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
577738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
577838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj/* Vector by scalar shift of E by an immediate byte.  This is a
577938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   straight copy of dis_SSE_shiftE_imm. */
578038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
578138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardjstatic
578255085f8680acc89d727e321f3b34cae1a8c4093aflorianUInt dis_MMX_shiftE_imm ( Int delta, const HChar* opname, IROp op )
578338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj{
578438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   Bool    shl, shr, sar;
578538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   UChar   rm   = getIByte(delta);
578638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  e0   = newTemp(Ity_I64);
578738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  e1   = newTemp(Ity_I64);
578838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   UChar   amt, size;
578938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   vassert(epartIsReg(rm));
579038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   vassert(gregOfRM(rm) == 2
579138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj           || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
57922d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj   amt = getIByte(delta+1);
579338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   delta += 2;
579438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   DIP("%s $%d,%s\n", opname,
579538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                      (Int)amt,
579638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                      nameMMXReg(eregOfRM(rm)) );
579738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
579838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   assign( e0, getMMXReg(eregOfRM(rm)) );
579938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
580038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   shl = shr = sar = False;
580138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   size = 0;
580238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   switch (op) {
580338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShlN16x4: shl = True; size = 16; break;
580438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShlN32x2: shl = True; size = 32; break;
580538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_Shl64:    shl = True; size = 64; break;
580638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_SarN16x4: sar = True; size = 16; break;
580738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_SarN32x2: sar = True; size = 32; break;
580838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShrN16x4: shr = True; size = 16; break;
580938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShrN32x2: shr = True; size = 32; break;
581038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_Shr64:    shr = True; size = 64; break;
581138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      default: vassert(0);
581238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   }
581338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
581438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (shl || shr) {
5815ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      assign( e1, amt >= size
5816ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     ? mkU64(0)
5817ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     : binop(op, mkexpr(e0), mkU8(amt))
5818ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      );
581938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else
582038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (sar) {
5821ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      assign( e1, amt >= size
5822ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     ? binop(op, mkexpr(e0), mkU8(size-1))
5823ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     : binop(op, mkexpr(e0), mkU8(amt))
5824ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      );
582538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else {
5826ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      /*NOTREACHED*/
582738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      vassert(0);
582838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   }
582938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
583038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   putMMXReg( eregOfRM(rm), mkexpr(e1) );
583138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   return delta;
583238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj}
583338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
583438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
583538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj/* Completely handle all MMX instructions except emms. */
5836464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5837464efa446b2db97115d3e5f04af5db3464cc0e93sewardjstatic
583852d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, Int delta )
5839464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
5840464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   Int   len;
5841464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   UChar modrm;
5842c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
5843464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   UChar opc = getIByte(delta);
5844464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   delta++;
5845464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
58464cb918d355cef4e7640d374346852db4556f3524sewardj   /* dis_MMX handles all insns except emms. */
58474cb918d355cef4e7640d374346852db4556f3524sewardj   do_MMX_preamble();
5848464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5849464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   switch (opc) {
5850464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
58512b7a9208ee96939f12896085a143891160dc539asewardj      case 0x6E:
58522b7a9208ee96939f12896085a143891160dc539asewardj         /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
58539df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
58549df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
58552b7a9208ee96939f12896085a143891160dc539asewardj         modrm = getIByte(delta);
58562b7a9208ee96939f12896085a143891160dc539asewardj         if (epartIsReg(modrm)) {
58572b7a9208ee96939f12896085a143891160dc539asewardj            delta++;
58582b7a9208ee96939f12896085a143891160dc539asewardj            putMMXReg(
58592b7a9208ee96939f12896085a143891160dc539asewardj               gregOfRM(modrm),
58602b7a9208ee96939f12896085a143891160dc539asewardj               binop( Iop_32HLto64,
58612b7a9208ee96939f12896085a143891160dc539asewardj                      mkU32(0),
58622b7a9208ee96939f12896085a143891160dc539asewardj                      getIReg(4, eregOfRM(modrm)) ) );
58632b7a9208ee96939f12896085a143891160dc539asewardj            DIP("movd %s, %s\n",
58642b7a9208ee96939f12896085a143891160dc539asewardj                nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
58652b7a9208ee96939f12896085a143891160dc539asewardj         } else {
58662b7a9208ee96939f12896085a143891160dc539asewardj            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
58672b7a9208ee96939f12896085a143891160dc539asewardj            delta += len;
58682b7a9208ee96939f12896085a143891160dc539asewardj            putMMXReg(
58692b7a9208ee96939f12896085a143891160dc539asewardj               gregOfRM(modrm),
58702b7a9208ee96939f12896085a143891160dc539asewardj               binop( Iop_32HLto64,
58712b7a9208ee96939f12896085a143891160dc539asewardj                      mkU32(0),
58722b7a9208ee96939f12896085a143891160dc539asewardj                      loadLE(Ity_I32, mkexpr(addr)) ) );
58732b7a9208ee96939f12896085a143891160dc539asewardj            DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
58742b7a9208ee96939f12896085a143891160dc539asewardj         }
58752b7a9208ee96939f12896085a143891160dc539asewardj         break;
58762b7a9208ee96939f12896085a143891160dc539asewardj
58772b7a9208ee96939f12896085a143891160dc539asewardj      case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
58789df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
58799df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
58802b7a9208ee96939f12896085a143891160dc539asewardj         modrm = getIByte(delta);
58812b7a9208ee96939f12896085a143891160dc539asewardj         if (epartIsReg(modrm)) {
58822b7a9208ee96939f12896085a143891160dc539asewardj            delta++;
58832b7a9208ee96939f12896085a143891160dc539asewardj            putIReg( 4, eregOfRM(modrm),
58842b7a9208ee96939f12896085a143891160dc539asewardj                     unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
58852b7a9208ee96939f12896085a143891160dc539asewardj            DIP("movd %s, %s\n",
58862b7a9208ee96939f12896085a143891160dc539asewardj                nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
58872b7a9208ee96939f12896085a143891160dc539asewardj         } else {
58882b7a9208ee96939f12896085a143891160dc539asewardj            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
58892b7a9208ee96939f12896085a143891160dc539asewardj            delta += len;
58902b7a9208ee96939f12896085a143891160dc539asewardj            storeLE( mkexpr(addr),
58912b7a9208ee96939f12896085a143891160dc539asewardj                     unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
58922b7a9208ee96939f12896085a143891160dc539asewardj            DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
58932b7a9208ee96939f12896085a143891160dc539asewardj         }
58942b7a9208ee96939f12896085a143891160dc539asewardj         break;
58952b7a9208ee96939f12896085a143891160dc539asewardj
5896464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0x6F:
5897464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
58989df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
58999df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5900464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         modrm = getIByte(delta);
5901464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         if (epartIsReg(modrm)) {
5902464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            delta++;
5903464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5904464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            DIP("movq %s, %s\n",
5905464efa446b2db97115d3e5f04af5db3464cc0e93sewardj                nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5906464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         } else {
5907464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5908464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            delta += len;
5909464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5910464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            DIP("movq %s, %s\n",
5911464efa446b2db97115d3e5f04af5db3464cc0e93sewardj                dis_buf, nameMMXReg(gregOfRM(modrm)));
5912464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         }
5913464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5914a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
5915464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0x7F:
5916464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
59179df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59189df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5919464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         modrm = getIByte(delta);
5920464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         if (epartIsReg(modrm)) {
59219ca2640e485edd83d16249ad29b40b081e273dedsewardj            delta++;
59229ca2640e485edd83d16249ad29b40b081e273dedsewardj            putMMXReg( eregOfRM(modrm), getMMXReg(gregOfRM(modrm)) );
59239ca2640e485edd83d16249ad29b40b081e273dedsewardj            DIP("movq %s, %s\n",
59249ca2640e485edd83d16249ad29b40b081e273dedsewardj                nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
5925464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         } else {
5926464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5927464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            delta += len;
5928893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj            storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
5929464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            DIP("mov(nt)q %s, %s\n",
5930464efa446b2db97115d3e5f04af5db3464cc0e93sewardj                nameMMXReg(gregOfRM(modrm)), dis_buf);
5931464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         }
5932464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5933464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59344340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xFC:
59354340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xFD:
59364340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
59379df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59389df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5939464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5940464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5941464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59424340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xEC:
59434340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
59449df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59459df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5946464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5947464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5948464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59494340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xDC:
59504340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
59519df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59529df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5953464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5954464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5955464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59564340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xF8:
59574340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xF9:
59584340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
59599df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59609df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5961464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
5962464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5963464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59644340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xE8:
59654340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
59669df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59679df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5968464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5969464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5970464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59714340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xD8:
59724340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
59739df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59749df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5975464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5976464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5977464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5978464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
59799df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59809df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5981464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5982464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5983464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5984464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
59859df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59869df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5987464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5988464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5989464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59904340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
59914340dac5c2cede4962868e6da5b73282da2bc465sewardj         vassert(sz == 4);
59924340dac5c2cede4962868e6da5b73282da2bc465sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
59934340dac5c2cede4962868e6da5b73282da2bc465sewardj         break;
59944340dac5c2cede4962868e6da5b73282da2bc465sewardj
59954340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x74:
59964340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x75:
59974340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
59989df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59999df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
60004340dac5c2cede4962868e6da5b73282da2bc465sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
60014340dac5c2cede4962868e6da5b73282da2bc465sewardj         break;
60024340dac5c2cede4962868e6da5b73282da2bc465sewardj
60034340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x64:
60044340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x65:
60054340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
60069df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60079df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
60084340dac5c2cede4962868e6da5b73282da2bc465sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
60094340dac5c2cede4962868e6da5b73282da2bc465sewardj         break;
60104340dac5c2cede4962868e6da5b73282da2bc465sewardj
601163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
60129df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60139df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
601463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
601563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
601663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
601763ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
60189df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60199df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
602063ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
602163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
602263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
602363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
60249df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60259df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
602663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
602763ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
602863ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
602963ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x68:
603063ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x69:
603163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
60329df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60339df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
603463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
603563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
603663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
603763ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x60:
603863ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x61:
603963ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
60409df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60419df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
604263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
604363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
604463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
604563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
60469df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60479df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
604863ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
604963ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
605063ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
605163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
60529df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60539df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
605463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
605563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
605663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
605763ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
60589df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60599df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
606063ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
606163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
606263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
606363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
60649df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60659df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
606663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
606738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj         break;
606863ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
606938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj#     define SHIFT_BY_REG(_name,_op)                                 \
607038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
607138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                break;
60728d14a59858e2464baa217f19daff83562f3cdca0sewardj
607338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
607438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
607538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
607638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
60778d14a59858e2464baa217f19daff83562f3cdca0sewardj
607838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
607938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
608038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
608138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
608238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
608338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
608438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
608538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
608638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
608738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj#     undef SHIFT_BY_REG
60888d14a59858e2464baa217f19daff83562f3cdca0sewardj
60892b7a9208ee96939f12896085a143891160dc539asewardj      case 0x71:
60902b7a9208ee96939f12896085a143891160dc539asewardj      case 0x72:
60912b7a9208ee96939f12896085a143891160dc539asewardj      case 0x73: {
60922b7a9208ee96939f12896085a143891160dc539asewardj         /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
6093a8415ffe6c6f0e73519301a55026a4071c701fd1sewardj         UChar byte2, subopc;
609438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj         if (sz != 4)
609538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj            goto mmx_decode_failure;
609638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj         byte2  = getIByte(delta);           /* amode / sub-opcode */
60979b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         subopc = toUChar( (byte2 >> 3) & 7 );
60982b7a9208ee96939f12896085a143891160dc539asewardj
609938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj#        define SHIFT_BY_IMM(_name,_op)                         \
610038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj             do { delta = dis_MMX_shiftE_imm(delta,_name,_op);  \
610138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj             } while (0)
61022b7a9208ee96939f12896085a143891160dc539asewardj
61032b7a9208ee96939f12896085a143891160dc539asewardj              if (subopc == 2 /*SRL*/ && opc == 0x71)
610438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
61052b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 2 /*SRL*/ && opc == 0x72)
610638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
61072b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 2 /*SRL*/ && opc == 0x73)
610838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psrlq", Iop_Shr64);
61092b7a9208ee96939f12896085a143891160dc539asewardj
61102b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 4 /*SAR*/ && opc == 0x71)
611138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
61122b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 4 /*SAR*/ && opc == 0x72)
611338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
61142b7a9208ee96939f12896085a143891160dc539asewardj
61152b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 6 /*SHL*/ && opc == 0x71)
611638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
61172b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 6 /*SHL*/ && opc == 0x72)
611838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
61192b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 6 /*SHL*/ && opc == 0x73)
612038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psllq", Iop_Shl64);
61212b7a9208ee96939f12896085a143891160dc539asewardj
61222b7a9208ee96939f12896085a143891160dc539asewardj         else goto mmx_decode_failure;
61232b7a9208ee96939f12896085a143891160dc539asewardj
612438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj#        undef SHIFT_BY_IMM
61252b7a9208ee96939f12896085a143891160dc539asewardj         break;
61262b7a9208ee96939f12896085a143891160dc539asewardj      }
61272b7a9208ee96939f12896085a143891160dc539asewardj
6128d71ba837242cc470f622335b1c650bce8886a533sewardj      case 0xF7: {
6129d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp addr    = newTemp(Ity_I32);
6130d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp regD    = newTemp(Ity_I64);
6131d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp regM    = newTemp(Ity_I64);
6132d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp mask    = newTemp(Ity_I64);
6133d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp olddata = newTemp(Ity_I64);
6134d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp newdata = newTemp(Ity_I64);
6135d71ba837242cc470f622335b1c650bce8886a533sewardj
6136d71ba837242cc470f622335b1c650bce8886a533sewardj         modrm = getIByte(delta);
6137d71ba837242cc470f622335b1c650bce8886a533sewardj         if (sz != 4 || (!epartIsReg(modrm)))
6138d71ba837242cc470f622335b1c650bce8886a533sewardj            goto mmx_decode_failure;
6139d71ba837242cc470f622335b1c650bce8886a533sewardj         delta++;
6140d71ba837242cc470f622335b1c650bce8886a533sewardj
6141d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
6142d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( regM, getMMXReg( eregOfRM(modrm) ));
6143d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( regD, getMMXReg( gregOfRM(modrm) ));
6144d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( mask, binop(Iop_SarN8x8, mkexpr(regM), mkU8(7)) );
6145d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( olddata, loadLE( Ity_I64, mkexpr(addr) ));
6146d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( newdata,
6147d71ba837242cc470f622335b1c650bce8886a533sewardj                 binop(Iop_Or64,
6148d71ba837242cc470f622335b1c650bce8886a533sewardj                       binop(Iop_And64,
6149d71ba837242cc470f622335b1c650bce8886a533sewardj                             mkexpr(regD),
6150d71ba837242cc470f622335b1c650bce8886a533sewardj                             mkexpr(mask) ),
6151d71ba837242cc470f622335b1c650bce8886a533sewardj                       binop(Iop_And64,
6152d71ba837242cc470f622335b1c650bce8886a533sewardj                             mkexpr(olddata),
6153d71ba837242cc470f622335b1c650bce8886a533sewardj                             unop(Iop_Not64, mkexpr(mask)))) );
6154d71ba837242cc470f622335b1c650bce8886a533sewardj         storeLE( mkexpr(addr), mkexpr(newdata) );
6155d71ba837242cc470f622335b1c650bce8886a533sewardj         DIP("maskmovq %s,%s\n", nameMMXReg( eregOfRM(modrm) ),
6156d71ba837242cc470f622335b1c650bce8886a533sewardj                                 nameMMXReg( gregOfRM(modrm) ) );
6157d71ba837242cc470f622335b1c650bce8886a533sewardj         break;
6158d71ba837242cc470f622335b1c650bce8886a533sewardj      }
6159d71ba837242cc470f622335b1c650bce8886a533sewardj
61602b7a9208ee96939f12896085a143891160dc539asewardj      /* --- MMX decode failure --- */
6161464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      default:
61622b7a9208ee96939f12896085a143891160dc539asewardj      mmx_decode_failure:
6163464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         *decode_ok = False;
6164464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         return delta; /* ignored */
6165464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
6166464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   }
6167464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
6168464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   *decode_ok = True;
6169464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   return delta;
6170464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
6171464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
6172464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
6173464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*------------------------------------------------------------*/
6174464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*--- More misc arithmetic and other obscure insns.        ---*/
6175464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*------------------------------------------------------------*/
6176a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6177a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj/* Double length left and right shifts.  Apparently only required in
6178a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   v-size (no b- variant). */
6179a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardjstatic
6180a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardjUInt dis_SHLRD_Gv_Ev ( UChar sorb,
618152d049186d07991237a825ec88aa7f1f303edb70sewardj                       Int delta, UChar modrm,
6182a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                       Int sz,
6183a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                       IRExpr* shift_amt,
6184a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                       Bool amt_is_literal,
618555085f8680acc89d727e321f3b34cae1a8c4093aflorian                       const HChar* shift_amt_txt,
6186a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                       Bool left_shift )
6187a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj{
6188a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   /* shift_amt :: Ity_I8 is the amount to shift.  shift_amt_txt is used
6189a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      for printing it.   And eip on entry points at the modrm byte. */
6190a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   Int len;
6191c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
6192a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
61936d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRType ty       = szToITy(sz);
61946d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp gsrc     = newTemp(ty);
61956d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp esrc     = newTemp(ty);
619692d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp addr     = IRTemp_INVALID;
61976d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp tmpSH    = newTemp(Ity_I8);
619892d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp tmpL     = IRTemp_INVALID;
619992d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp tmpRes   = IRTemp_INVALID;
620092d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp tmpSubSh = IRTemp_INVALID;
6201a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   IROp   mkpair;
6202a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   IROp   getres;
6203a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   IROp   shift;
6204a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   IRExpr* mask = NULL;
6205a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6206a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   vassert(sz == 2 || sz == 4);
6207a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6208a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   /* The E-part is the destination; this is shifted.  The G-part
6209a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      supplies bits to be shifted into the E-part, but is not
6210a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      changed.
6211a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6212a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      If shifting left, form a double-length word with E at the top
6213a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      and G at the bottom, and shift this left.  The result is then in
6214a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      the high part.
6215a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6216a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      If shifting right, form a double-length word with G at the top
6217a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      and E at the bottom, and shift this right.  The result is then
6218a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      at the bottom.  */
6219a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6220a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   /* Fetch the operands. */
6221a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6222a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
6223a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6224a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   if (epartIsReg(modrm)) {
6225a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      delta++;
6226a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      assign( esrc, getIReg(sz, eregOfRM(modrm)) );
622768511549b138ef55c8d31088cb0f20a72d83ab2bsewardj      DIP("sh%cd%c %s, %s, %s\n",
6228a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj          ( left_shift ? 'l' : 'r' ), nameISize(sz),
622968511549b138ef55c8d31088cb0f20a72d83ab2bsewardj          shift_amt_txt,
6230a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj          nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
6231a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   } else {
6232a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      addr = disAMode ( &len, sorb, delta, dis_buf );
6233a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      delta += len;
6234a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      assign( esrc, loadLE(ty, mkexpr(addr)) );
623568511549b138ef55c8d31088cb0f20a72d83ab2bsewardj      DIP("sh%cd%c %s, %s, %s\n",
623668511549b138ef55c8d31088cb0f20a72d83ab2bsewardj          ( left_shift ? 'l' : 'r' ), nameISize(sz),
623768511549b138ef55c8d31088cb0f20a72d83ab2bsewardj          shift_amt_txt,
623868511549b138ef55c8d31088cb0f20a72d83ab2bsewardj          nameIReg(sz, gregOfRM(modrm)), dis_buf);
6239a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   }
6240a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6241a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   /* Round up the relevant primops. */
6242a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6243a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   if (sz == 4) {
6244a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      tmpL     = newTemp(Ity_I64);
6245a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      tmpRes   = newTemp(Ity_I32);
6246a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      tmpSubSh = newTemp(Ity_I32);
6247e539a4055b785d1ee978727e51bcc4b39f3e2c1asewardj      mkpair   = Iop_32HLto64;
62488c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      getres   = left_shift ? Iop_64HIto32 : Iop_64to32;
6249e539a4055b785d1ee978727e51bcc4b39f3e2c1asewardj      shift    = left_shift ? Iop_Shl64 : Iop_Shr64;
6250e539a4055b785d1ee978727e51bcc4b39f3e2c1asewardj      mask     = mkU8(31);
6251a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   } else {
6252a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      /* sz == 2 */
62538c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      tmpL     = newTemp(Ity_I32);
62548c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      tmpRes   = newTemp(Ity_I16);
62558c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      tmpSubSh = newTemp(Ity_I16);
62568c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      mkpair   = Iop_16HLto32;
62578c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      getres   = left_shift ? Iop_32HIto16 : Iop_32to16;
62588c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      shift    = left_shift ? Iop_Shl32 : Iop_Shr32;
62598c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      mask     = mkU8(15);
6260a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   }
6261a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6262a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   /* Do the shift, calculate the subshift value, and set
6263a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      the flag thunk. */
6264a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
62658c7f1abe9e022f6382634efea09c9cac89ec6336sewardj   assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
62668c7f1abe9e022f6382634efea09c9cac89ec6336sewardj
6267a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   if (left_shift)
6268a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
6269a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   else
6270a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
6271a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6272a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
6273a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   assign( tmpSubSh,
6274a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj           unop(getres,
6275a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                binop(shift,
6276a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                      mkexpr(tmpL),
6277a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                      binop(Iop_And8,
6278a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                            binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6279a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                            mask))) );
6280a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
62812a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
62822a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                              tmpRes, tmpSubSh, ty, tmpSH );
6283a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6284a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   /* Put result back. */
6285a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6286a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   if (epartIsReg(modrm)) {
6287a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
6288a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   } else {
6289a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      storeLE( mkexpr(addr), mkexpr(tmpRes) );
6290a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   }
6291a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6292a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   if (amt_is_literal) delta++;
6293a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   return delta;
6294a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj}
6295a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6296a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
62971c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj/* Handle BT/BTS/BTR/BTC Gv, Ev.  Apparently b-size is not
62981c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   required. */
62991c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63001c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardjtypedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
63011c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
630255085f8680acc89d727e321f3b34cae1a8c4093aflorianstatic const HChar* nameBtOp ( BtOp op )
63031c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj{
63041c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   switch (op) {
63051c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case BtOpNone:  return "";
63061c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case BtOpSet:   return "s";
63071c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case BtOpReset: return "r";
63081c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case BtOpComp:  return "c";
63091c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      default: vpanic("nameBtOp(x86)");
63101c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   }
63111c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj}
63121c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63131c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63141c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardjstatic
6315cacba8e675988fbf21b08feea1f317a9c896c053florianUInt dis_bt_G_E ( const VexAbiInfo* vbi,
63160283430ee809d645864ddd2da5f450f88142b4cdsewardj                  UChar sorb, Bool locked, Int sz, Int delta, BtOp op )
63171c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj{
6318c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar  dis_buf[50];
63191c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   UChar  modrm;
63201c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   Int    len;
63211c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
6322e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj          t_addr1, t_esp, t_mask, t_new;
63231c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63241c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   vassert(sz == 2 || sz == 4);
63251c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63261c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   t_fetched = t_bitno0 = t_bitno1 = t_bitno2
6327e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj             = t_addr0 = t_addr1 = t_esp
6328e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj             = t_mask = t_new = IRTemp_INVALID;
63291c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63301c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   t_fetched = newTemp(Ity_I8);
6331e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   t_new     = newTemp(Ity_I8);
63321c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   t_bitno0  = newTemp(Ity_I32);
63331c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   t_bitno1  = newTemp(Ity_I32);
63341c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   t_bitno2  = newTemp(Ity_I8);
63351c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   t_addr1   = newTemp(Ity_I32);
63361c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   modrm     = getIByte(delta);
63371c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63389ed1680d3094c6ecb6d9b8cbb58f7ef5d30b71b0sewardj   assign( t_bitno0, widenSto32(getIReg(sz, gregOfRM(modrm))) );
63391c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63401c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   if (epartIsReg(modrm)) {
63411c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      delta++;
63421c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      /* Get it onto the client's stack. */
63431c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      t_esp = newTemp(Ity_I32);
63441c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      t_addr0 = newTemp(Ity_I32);
63451c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63460283430ee809d645864ddd2da5f450f88142b4cdsewardj      /* For the choice of the value 128, see comment in dis_bt_G_E in
63470283430ee809d645864ddd2da5f450f88142b4cdsewardj         guest_amd64_toIR.c.  We point out here only that 128 is
63480283430ee809d645864ddd2da5f450f88142b4cdsewardj         fast-cased in Memcheck and is > 0, so seems like a good
63490283430ee809d645864ddd2da5f450f88142b4cdsewardj         choice. */
63500283430ee809d645864ddd2da5f450f88142b4cdsewardj      vassert(vbi->guest_stack_redzone_size == 0);
63510283430ee809d645864ddd2da5f450f88142b4cdsewardj      assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(128)) );
63521c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      putIReg(4, R_ESP, mkexpr(t_esp));
63531c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63541c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
63551c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63561c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      /* Make t_addr0 point at it. */
63571c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      assign( t_addr0, mkexpr(t_esp) );
63581c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63591c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      /* Mask out upper bits of the shift amount, since we're doing a
63601c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj         reg. */
63611c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      assign( t_bitno1, binop(Iop_And32,
63621c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                              mkexpr(t_bitno0),
63631c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                              mkU32(sz == 4 ? 31 : 15)) );
63641c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63651c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   } else {
63661c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
63671c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      delta += len;
63681c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      assign( t_bitno1, mkexpr(t_bitno0) );
63691c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   }
63701c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63711c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* At this point: t_addr0 is the address being operated on.  If it
63721c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      was a reg, we will have pushed it onto the client's stack.
63731c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      t_bitno1 is the bit number, suitably masked in the case of a
63741c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      reg.  */
63751c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63761c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* Now the main sequence. */
63771c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   assign( t_addr1,
63781c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj           binop(Iop_Add32,
63791c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                 mkexpr(t_addr0),
63801c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
63811c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63821c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* t_addr1 now holds effective address */
63831c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63841c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   assign( t_bitno2,
63851c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj           unop(Iop_32to8,
63861c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
63871c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63881c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* t_bitno2 contains offset of bit within byte */
63891c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63901c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   if (op != BtOpNone) {
63911c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      t_mask = newTemp(Ity_I8);
63921c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
63931c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   }
63944963a42df83976b446e204c7f1eb587021bd94a3sewardj
63951c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* t_mask is now a suitable byte mask */
63961c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63971c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
63981c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63991c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   if (op != BtOpNone) {
64001c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      switch (op) {
6401e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         case BtOpSet:
6402e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            assign( t_new,
6403e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                    binop(Iop_Or8, mkexpr(t_fetched), mkexpr(t_mask)) );
64041c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj            break;
6405e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         case BtOpComp:
6406e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            assign( t_new,
6407e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                    binop(Iop_Xor8, mkexpr(t_fetched), mkexpr(t_mask)) );
64081c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj            break;
6409e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         case BtOpReset:
6410e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            assign( t_new,
6411e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                    binop(Iop_And8, mkexpr(t_fetched),
6412e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                    unop(Iop_Not8, mkexpr(t_mask))) );
64131c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj            break;
64141c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj         default:
64151c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj            vpanic("dis_bt_G_E(x86)");
64161c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      }
6417e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      if (locked && !epartIsReg(modrm)) {
6418e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         casLE( mkexpr(t_addr1), mkexpr(t_fetched)/*expd*/,
6419e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                 mkexpr(t_new)/*new*/,
6420e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                 guest_EIP_curr_instr );
6421e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      } else {
6422e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         storeLE( mkexpr(t_addr1), mkexpr(t_new) );
6423e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      }
64241c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   }
64251c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
64261c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* Side effect done; now get selected bit into Carry flag */
64272a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
64282a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
64292a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
64301c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   stmt( IRStmt_Put(
64312a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            OFFB_CC_DEP1,
64321c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj            binop(Iop_And32,
64331c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                  binop(Iop_Shr32,
64341c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                        unop(Iop_8Uto32, mkexpr(t_fetched)),
64355bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                        mkexpr(t_bitno2)),
64365bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                  mkU32(1)))
64371c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj       );
6438a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
6439a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      elimination of previous stores to this field work better. */
6440a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
64411c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
64421c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* Move reg operand from stack back to reg */
64431c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   if (epartIsReg(modrm)) {
64441c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      /* t_esp still points at it. */
64454963a42df83976b446e204c7f1eb587021bd94a3sewardj      putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
64460283430ee809d645864ddd2da5f450f88142b4cdsewardj      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(128)) );
64471c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   }
64481c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
64491c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   DIP("bt%s%c %s, %s\n",
64501c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj       nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
64511c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj       ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
64521c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
64531c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   return delta;
64541c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj}
6455ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6456ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6457ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6458ce646f23d71ac432c340667387aa4a5ce7d18099sewardj/* Handle BSF/BSR.  Only v-size seems necessary. */
6459ce646f23d71ac432c340667387aa4a5ce7d18099sewardjstatic
646052d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_bs_E_G ( UChar sorb, Int sz, Int delta, Bool fwds )
6461ce646f23d71ac432c340667387aa4a5ce7d18099sewardj{
6462ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   Bool   isReg;
6463ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   UChar  modrm;
6464c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar  dis_buf[50];
6465ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6466ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   IRType ty  = szToITy(sz);
6467ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   IRTemp src = newTemp(ty);
6468ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   IRTemp dst = newTemp(ty);
6469ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6470ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   IRTemp src32 = newTemp(Ity_I32);
6471ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   IRTemp dst32 = newTemp(Ity_I32);
6472009230b9758291b594e60d7c0243a73d53e81854sewardj   IRTemp srcB  = newTemp(Ity_I1);
6473ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6474ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   vassert(sz == 4 || sz == 2);
6475ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6476ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   modrm = getIByte(delta);
6477ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6478ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   isReg = epartIsReg(modrm);
6479ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   if (isReg) {
6480ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      delta++;
6481ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      assign( src, getIReg(sz, eregOfRM(modrm)) );
6482ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   } else {
6483ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      Int    len;
6484ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6485ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      delta += len;
6486ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      assign( src, loadLE(ty, mkexpr(addr)) );
6487ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   }
6488ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6489ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   DIP("bs%c%c %s, %s\n",
6490ce646f23d71ac432c340667387aa4a5ce7d18099sewardj       fwds ? 'f' : 'r', nameISize(sz),
6491ce646f23d71ac432c340667387aa4a5ce7d18099sewardj       ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
6492ce646f23d71ac432c340667387aa4a5ce7d18099sewardj       nameIReg(sz, gregOfRM(modrm)));
6493ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6494009230b9758291b594e60d7c0243a73d53e81854sewardj   /* Generate a bool expression which is zero iff the original is
6495e13074c2c1321d069fb95806bdce64f9a3512341sewardj      zero, and nonzero otherwise.  Ask for a CmpNE version which, if
6496e13074c2c1321d069fb95806bdce64f9a3512341sewardj      instrumented by Memcheck, is instrumented expensively, since
6497e13074c2c1321d069fb95806bdce64f9a3512341sewardj      this may be used on the output of a preceding movmskb insn,
6498e13074c2c1321d069fb95806bdce64f9a3512341sewardj      which has been known to be partially defined, and in need of
6499e13074c2c1321d069fb95806bdce64f9a3512341sewardj      careful handling. */
6500009230b9758291b594e60d7c0243a73d53e81854sewardj   assign( srcB, binop(mkSizedOp(ty,Iop_ExpCmpNE8),
6501009230b9758291b594e60d7c0243a73d53e81854sewardj                       mkexpr(src), mkU(ty,0)) );
6502ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6503ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   /* Flags: Z is 1 iff source value is zero.  All others
6504ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      are undefined -- we force them to zero. */
65052a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
65062a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6507ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   stmt( IRStmt_Put(
65082a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            OFFB_CC_DEP1,
650999dd03e04a6914d90d5fee727d61d76905334becflorian            IRExpr_ITE( mkexpr(srcB),
651099dd03e04a6914d90d5fee727d61d76905334becflorian                        /* src!=0 */
651199dd03e04a6914d90d5fee727d61d76905334becflorian                        mkU32(0),
651299dd03e04a6914d90d5fee727d61d76905334becflorian                        /* src==0 */
651399dd03e04a6914d90d5fee727d61d76905334becflorian                        mkU32(X86G_CC_MASK_Z)
6514ce646f23d71ac432c340667387aa4a5ce7d18099sewardj                        )
6515ce646f23d71ac432c340667387aa4a5ce7d18099sewardj       ));
6516a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
6517a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      elimination of previous stores to this field work better. */
6518a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
6519ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6520ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   /* Result: iff source value is zero, we can't use
6521ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
6522ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      But anyway, Intel x86 semantics say the result is undefined in
6523ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      such situations.  Hence handle the zero case specially. */
6524ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6525ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   /* Bleh.  What we compute:
6526ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6527ce646f23d71ac432c340667387aa4a5ce7d18099sewardj          bsf32:  if src == 0 then 0 else  Ctz32(src)
6528ce646f23d71ac432c340667387aa4a5ce7d18099sewardj          bsr32:  if src == 0 then 0 else  31 - Clz32(src)
6529ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6530ce646f23d71ac432c340667387aa4a5ce7d18099sewardj          bsf16:  if src == 0 then 0 else  Ctz32(16Uto32(src))
6531ce646f23d71ac432c340667387aa4a5ce7d18099sewardj          bsr16:  if src == 0 then 0 else  31 - Clz32(16Uto32(src))
6532ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6533ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      First, widen src to 32 bits if it is not already.
653437158719b222a3776df257a80c8ce44d810fae82sewardj
653537158719b222a3776df257a80c8ce44d810fae82sewardj      Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
653637158719b222a3776df257a80c8ce44d810fae82sewardj      dst register unchanged when src == 0.  Hence change accordingly.
6537ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   */
6538ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   if (sz == 2)
6539ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
6540ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   else
6541ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      assign( src32, mkexpr(src) );
6542ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6543ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   /* The main computation, guarding against zero. */
6544ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   assign( dst32,
654599dd03e04a6914d90d5fee727d61d76905334becflorian           IRExpr_ITE(
6546009230b9758291b594e60d7c0243a73d53e81854sewardj              mkexpr(srcB),
6547ce646f23d71ac432c340667387aa4a5ce7d18099sewardj              /* src != 0 */
6548ce646f23d71ac432c340667387aa4a5ce7d18099sewardj              fwds ? unop(Iop_Ctz32, mkexpr(src32))
6549ce646f23d71ac432c340667387aa4a5ce7d18099sewardj                   : binop(Iop_Sub32,
6550ce646f23d71ac432c340667387aa4a5ce7d18099sewardj                           mkU32(31),
655199dd03e04a6914d90d5fee727d61d76905334becflorian                           unop(Iop_Clz32, mkexpr(src32))),
655299dd03e04a6914d90d5fee727d61d76905334becflorian              /* src == 0 -- leave dst unchanged */
655399dd03e04a6914d90d5fee727d61d76905334becflorian              widenUto32( getIReg( sz, gregOfRM(modrm) ) )
6554ce646f23d71ac432c340667387aa4a5ce7d18099sewardj           )
6555ce646f23d71ac432c340667387aa4a5ce7d18099sewardj         );
6556ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6557ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   if (sz == 2)
6558ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
6559ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   else
6560ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      assign( dst, mkexpr(dst32) );
6561ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6562ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   /* dump result back */
6563ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
6564ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6565ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   return delta;
6566ce646f23d71ac432c340667387aa4a5ce7d18099sewardj}
656764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
656864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
656964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
657064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjvoid codegen_xchg_eAX_Reg ( Int sz, Int reg )
657164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
657264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRType ty = szToITy(sz);
657364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp t1 = newTemp(ty);
657464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp t2 = newTemp(ty);
657564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   vassert(sz == 2 || sz == 4);
657664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( t1, getIReg(sz, R_EAX) );
657764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( t2, getIReg(sz, reg) );
657864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg( sz, R_EAX, mkexpr(t2) );
657964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg( sz, reg, mkexpr(t1) );
658064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   DIP("xchg%c %s, %s\n",
658164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj       nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
658264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
658364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
658464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
6585bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardjstatic
6586bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardjvoid codegen_SAHF ( void )
6587bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj{
6588bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   /* Set the flags to:
65892a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      (x86g_calculate_flags_all() & X86G_CC_MASK_O)  -- retain the old O flag
65902a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
65912a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                |X86G_CC_MASK_P|X86G_CC_MASK_C)
6592bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   */
65932a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   UInt   mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
65942a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                       |X86G_CC_MASK_C|X86G_CC_MASK_P;
6595bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   IRTemp oldflags   = newTemp(Ity_I32);
65962a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   assign( oldflags, mk_x86g_calculate_eflags_all() );
65972a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
6598905edbde84c49991a1f27c726eda02b338460c8esewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
65992a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
66002a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP1,
6601bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         binop(Iop_Or32,
66022a9ad023890d3b34cf45e429df2a8ae88b419128sewardj               binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
6603bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               binop(Iop_And32,
6604bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj                     binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
6605bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj                     mkU32(mask_SZACP))
6606bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj              )
6607bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   ));
6608a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
6609a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      elimination of previous stores to this field work better. */
6610a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
6611bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj}
6612bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
6613bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
66148dfdc8a059e35940fe96371360cae39d9724cea9sewardjstatic
66158dfdc8a059e35940fe96371360cae39d9724cea9sewardjvoid codegen_LAHF ( void  )
66168dfdc8a059e35940fe96371360cae39d9724cea9sewardj{
66178dfdc8a059e35940fe96371360cae39d9724cea9sewardj   /* AH <- EFLAGS(SF:ZF:0:AF:0:PF:1:CF) */
66188dfdc8a059e35940fe96371360cae39d9724cea9sewardj   IRExpr* eax_with_hole;
66198dfdc8a059e35940fe96371360cae39d9724cea9sewardj   IRExpr* new_byte;
66208dfdc8a059e35940fe96371360cae39d9724cea9sewardj   IRExpr* new_eax;
66218dfdc8a059e35940fe96371360cae39d9724cea9sewardj   UInt    mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
66228dfdc8a059e35940fe96371360cae39d9724cea9sewardj                        |X86G_CC_MASK_C|X86G_CC_MASK_P;
66238dfdc8a059e35940fe96371360cae39d9724cea9sewardj
66248dfdc8a059e35940fe96371360cae39d9724cea9sewardj   IRTemp  flags = newTemp(Ity_I32);
66258dfdc8a059e35940fe96371360cae39d9724cea9sewardj   assign( flags, mk_x86g_calculate_eflags_all() );
66268dfdc8a059e35940fe96371360cae39d9724cea9sewardj
66278dfdc8a059e35940fe96371360cae39d9724cea9sewardj   eax_with_hole
66288dfdc8a059e35940fe96371360cae39d9724cea9sewardj      = binop(Iop_And32, getIReg(4, R_EAX), mkU32(0xFFFF00FF));
66298dfdc8a059e35940fe96371360cae39d9724cea9sewardj   new_byte
66308dfdc8a059e35940fe96371360cae39d9724cea9sewardj      = binop(Iop_Or32, binop(Iop_And32, mkexpr(flags), mkU32(mask_SZACP)),
66318dfdc8a059e35940fe96371360cae39d9724cea9sewardj                        mkU32(1<<1));
66328dfdc8a059e35940fe96371360cae39d9724cea9sewardj   new_eax
66338dfdc8a059e35940fe96371360cae39d9724cea9sewardj      = binop(Iop_Or32, eax_with_hole,
66348dfdc8a059e35940fe96371360cae39d9724cea9sewardj                        binop(Iop_Shl32, new_byte, mkU8(8)));
66358dfdc8a059e35940fe96371360cae39d9724cea9sewardj   putIReg(4, R_EAX, new_eax);
66368dfdc8a059e35940fe96371360cae39d9724cea9sewardj}
66378dfdc8a059e35940fe96371360cae39d9724cea9sewardj
6638458a6f8809554fc459d90043e032f7c579620c97sewardj
6639458a6f8809554fc459d90043e032f7c579620c97sewardjstatic
6640458a6f8809554fc459d90043e032f7c579620c97sewardjUInt dis_cmpxchg_G_E ( UChar       sorb,
6641e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                       Bool        locked,
6642458a6f8809554fc459d90043e032f7c579620c97sewardj                       Int         size,
664352d049186d07991237a825ec88aa7f1f303edb70sewardj                       Int         delta0 )
6644458a6f8809554fc459d90043e032f7c579620c97sewardj{
6645c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
6646458a6f8809554fc459d90043e032f7c579620c97sewardj   Int   len;
6647458a6f8809554fc459d90043e032f7c579620c97sewardj
6648458a6f8809554fc459d90043e032f7c579620c97sewardj   IRType ty    = szToITy(size);
6649458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp acc   = newTemp(ty);
6650458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp src   = newTemp(ty);
6651458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp dest  = newTemp(ty);
6652458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp dest2 = newTemp(ty);
6653458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp acc2  = newTemp(ty);
6654009230b9758291b594e60d7c0243a73d53e81854sewardj   IRTemp cond  = newTemp(Ity_I1);
665592d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp addr  = IRTemp_INVALID;
6656458a6f8809554fc459d90043e032f7c579620c97sewardj   UChar  rm    = getUChar(delta0);
6657458a6f8809554fc459d90043e032f7c579620c97sewardj
6658e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* There are 3 cases to consider:
6659e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6660e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      reg-reg: ignore any lock prefix, generate sequence based
666199dd03e04a6914d90d5fee727d61d76905334becflorian               on ITE
6662e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6663e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      reg-mem, not locked: ignore any lock prefix, generate sequence
666499dd03e04a6914d90d5fee727d61d76905334becflorian                           based on ITE
6665e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6666e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      reg-mem, locked: use IRCAS
6667e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   */
6668458a6f8809554fc459d90043e032f7c579620c97sewardj   if (epartIsReg(rm)) {
6669e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* case 1 */
6670458a6f8809554fc459d90043e032f7c579620c97sewardj      assign( dest, getIReg(size, eregOfRM(rm)) );
6671458a6f8809554fc459d90043e032f7c579620c97sewardj      delta0++;
6672e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( src, getIReg(size, gregOfRM(rm)) );
6673e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( acc, getIReg(size, R_EAX) );
6674e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6675009230b9758291b594e60d7c0243a73d53e81854sewardj      assign( cond, mk_x86g_calculate_condition(X86CondZ) );
667699dd03e04a6914d90d5fee727d61d76905334becflorian      assign( dest2, IRExpr_ITE(mkexpr(cond), mkexpr(src), mkexpr(dest)) );
667799dd03e04a6914d90d5fee727d61d76905334becflorian      assign( acc2,  IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
6678e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      putIReg(size, R_EAX, mkexpr(acc2));
6679e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      putIReg(size, eregOfRM(rm), mkexpr(dest2));
6680458a6f8809554fc459d90043e032f7c579620c97sewardj      DIP("cmpxchg%c %s,%s\n", nameISize(size),
6681458a6f8809554fc459d90043e032f7c579620c97sewardj                               nameIReg(size,gregOfRM(rm)),
6682458a6f8809554fc459d90043e032f7c579620c97sewardj                               nameIReg(size,eregOfRM(rm)) );
6683e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
6684e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   else if (!epartIsReg(rm) && !locked) {
6685e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* case 2 */
6686458a6f8809554fc459d90043e032f7c579620c97sewardj      addr = disAMode ( &len, sorb, delta0, dis_buf );
6687458a6f8809554fc459d90043e032f7c579620c97sewardj      assign( dest, loadLE(ty, mkexpr(addr)) );
6688458a6f8809554fc459d90043e032f7c579620c97sewardj      delta0 += len;
6689e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( src, getIReg(size, gregOfRM(rm)) );
6690e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( acc, getIReg(size, R_EAX) );
6691e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6692009230b9758291b594e60d7c0243a73d53e81854sewardj      assign( cond, mk_x86g_calculate_condition(X86CondZ) );
669399dd03e04a6914d90d5fee727d61d76905334becflorian      assign( dest2, IRExpr_ITE(mkexpr(cond), mkexpr(src), mkexpr(dest)) );
669499dd03e04a6914d90d5fee727d61d76905334becflorian      assign( acc2,  IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
6695e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      putIReg(size, R_EAX, mkexpr(acc2));
6696e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      storeLE( mkexpr(addr), mkexpr(dest2) );
6697458a6f8809554fc459d90043e032f7c579620c97sewardj      DIP("cmpxchg%c %s,%s\n", nameISize(size),
6698458a6f8809554fc459d90043e032f7c579620c97sewardj                               nameIReg(size,gregOfRM(rm)), dis_buf);
6699458a6f8809554fc459d90043e032f7c579620c97sewardj   }
6700e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   else if (!epartIsReg(rm) && locked) {
6701e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* case 3 */
6702e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* src is new value.  acc is expected value.  dest is old value.
6703e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         Compute success from the output of the IRCAS, and steer the
6704e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         new value for EAX accordingly: in case of success, EAX is
6705e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         unchanged. */
6706e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      addr = disAMode ( &len, sorb, delta0, dis_buf );
6707e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta0 += len;
6708e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( src, getIReg(size, gregOfRM(rm)) );
6709e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( acc, getIReg(size, R_EAX) );
6710e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      stmt( IRStmt_CAS(
6711e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         mkIRCAS( IRTemp_INVALID, dest, Iend_LE, mkexpr(addr),
6712e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  NULL, mkexpr(acc), NULL, mkexpr(src) )
6713e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      ));
6714e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6715009230b9758291b594e60d7c0243a73d53e81854sewardj      assign( cond, mk_x86g_calculate_condition(X86CondZ) );
671699dd03e04a6914d90d5fee727d61d76905334becflorian      assign( acc2,  IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
6717e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      putIReg(size, R_EAX, mkexpr(acc2));
671840d1d2126f109fc8fce807320d06ef2a775c0852sewardj      DIP("cmpxchg%c %s,%s\n", nameISize(size),
671940d1d2126f109fc8fce807320d06ef2a775c0852sewardj                               nameIReg(size,gregOfRM(rm)), dis_buf);
6720458a6f8809554fc459d90043e032f7c579620c97sewardj   }
6721e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   else vassert(0);
6722458a6f8809554fc459d90043e032f7c579620c97sewardj
6723458a6f8809554fc459d90043e032f7c579620c97sewardj   return delta0;
6724458a6f8809554fc459d90043e032f7c579620c97sewardj}
6725458a6f8809554fc459d90043e032f7c579620c97sewardj
6726458a6f8809554fc459d90043e032f7c579620c97sewardj
6727458a6f8809554fc459d90043e032f7c579620c97sewardj/* Handle conditional move instructions of the form
6728458a6f8809554fc459d90043e032f7c579620c97sewardj      cmovcc E(reg-or-mem), G(reg)
6729458a6f8809554fc459d90043e032f7c579620c97sewardj
6730458a6f8809554fc459d90043e032f7c579620c97sewardj   E(src) is reg-or-mem
6731458a6f8809554fc459d90043e032f7c579620c97sewardj   G(dst) is reg.
6732458a6f8809554fc459d90043e032f7c579620c97sewardj
6733458a6f8809554fc459d90043e032f7c579620c97sewardj   If E is reg, -->    GET %E, tmps
6734458a6f8809554fc459d90043e032f7c579620c97sewardj                       GET %G, tmpd
6735458a6f8809554fc459d90043e032f7c579620c97sewardj                       CMOVcc tmps, tmpd
6736458a6f8809554fc459d90043e032f7c579620c97sewardj                       PUT tmpd, %G
6737458a6f8809554fc459d90043e032f7c579620c97sewardj
6738458a6f8809554fc459d90043e032f7c579620c97sewardj   If E is mem  -->    (getAddr E) -> tmpa
6739458a6f8809554fc459d90043e032f7c579620c97sewardj                       LD (tmpa), tmps
6740458a6f8809554fc459d90043e032f7c579620c97sewardj                       GET %G, tmpd
6741458a6f8809554fc459d90043e032f7c579620c97sewardj                       CMOVcc tmps, tmpd
6742458a6f8809554fc459d90043e032f7c579620c97sewardj                       PUT tmpd, %G
6743458a6f8809554fc459d90043e032f7c579620c97sewardj*/
6744458a6f8809554fc459d90043e032f7c579620c97sewardjstatic
6745458a6f8809554fc459d90043e032f7c579620c97sewardjUInt dis_cmov_E_G ( UChar       sorb,
6746458a6f8809554fc459d90043e032f7c579620c97sewardj                    Int         sz,
67472a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                    X86Condcode cond,
674852d049186d07991237a825ec88aa7f1f303edb70sewardj                    Int         delta0 )
6749458a6f8809554fc459d90043e032f7c579620c97sewardj{
6750458a6f8809554fc459d90043e032f7c579620c97sewardj   UChar rm  = getIByte(delta0);
6751c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
6752458a6f8809554fc459d90043e032f7c579620c97sewardj   Int   len;
6753458a6f8809554fc459d90043e032f7c579620c97sewardj
6754883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   IRType ty   = szToITy(sz);
6755458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp tmps = newTemp(ty);
6756458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp tmpd = newTemp(ty);
6757458a6f8809554fc459d90043e032f7c579620c97sewardj
6758458a6f8809554fc459d90043e032f7c579620c97sewardj   if (epartIsReg(rm)) {
6759458a6f8809554fc459d90043e032f7c579620c97sewardj      assign( tmps, getIReg(sz, eregOfRM(rm)) );
6760458a6f8809554fc459d90043e032f7c579620c97sewardj      assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6761458a6f8809554fc459d90043e032f7c579620c97sewardj
6762458a6f8809554fc459d90043e032f7c579620c97sewardj      putIReg(sz, gregOfRM(rm),
676399dd03e04a6914d90d5fee727d61d76905334becflorian                  IRExpr_ITE( mk_x86g_calculate_condition(cond),
676499dd03e04a6914d90d5fee727d61d76905334becflorian                              mkexpr(tmps),
676599dd03e04a6914d90d5fee727d61d76905334becflorian                              mkexpr(tmpd) )
6766458a6f8809554fc459d90043e032f7c579620c97sewardj             );
6767458a6f8809554fc459d90043e032f7c579620c97sewardj      DIP("cmov%c%s %s,%s\n", nameISize(sz),
67682a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                              name_X86Condcode(cond),
6769458a6f8809554fc459d90043e032f7c579620c97sewardj                              nameIReg(sz,eregOfRM(rm)),
6770458a6f8809554fc459d90043e032f7c579620c97sewardj                              nameIReg(sz,gregOfRM(rm)));
6771458a6f8809554fc459d90043e032f7c579620c97sewardj      return 1+delta0;
6772458a6f8809554fc459d90043e032f7c579620c97sewardj   }
6773458a6f8809554fc459d90043e032f7c579620c97sewardj
6774458a6f8809554fc459d90043e032f7c579620c97sewardj   /* E refers to memory */
6775458a6f8809554fc459d90043e032f7c579620c97sewardj   {
6776458a6f8809554fc459d90043e032f7c579620c97sewardj      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6777458a6f8809554fc459d90043e032f7c579620c97sewardj      assign( tmps, loadLE(ty, mkexpr(addr)) );
6778458a6f8809554fc459d90043e032f7c579620c97sewardj      assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6779458a6f8809554fc459d90043e032f7c579620c97sewardj
6780458a6f8809554fc459d90043e032f7c579620c97sewardj      putIReg(sz, gregOfRM(rm),
678199dd03e04a6914d90d5fee727d61d76905334becflorian                  IRExpr_ITE( mk_x86g_calculate_condition(cond),
678299dd03e04a6914d90d5fee727d61d76905334becflorian                              mkexpr(tmps),
678399dd03e04a6914d90d5fee727d61d76905334becflorian                              mkexpr(tmpd) )
6784458a6f8809554fc459d90043e032f7c579620c97sewardj             );
6785458a6f8809554fc459d90043e032f7c579620c97sewardj
6786458a6f8809554fc459d90043e032f7c579620c97sewardj      DIP("cmov%c%s %s,%s\n", nameISize(sz),
67872a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                              name_X86Condcode(cond),
6788458a6f8809554fc459d90043e032f7c579620c97sewardj                              dis_buf,
6789458a6f8809554fc459d90043e032f7c579620c97sewardj                              nameIReg(sz,gregOfRM(rm)));
6790458a6f8809554fc459d90043e032f7c579620c97sewardj      return len+delta0;
6791458a6f8809554fc459d90043e032f7c579620c97sewardj   }
6792458a6f8809554fc459d90043e032f7c579620c97sewardj}
6793458a6f8809554fc459d90043e032f7c579620c97sewardj
6794458a6f8809554fc459d90043e032f7c579620c97sewardj
6795883b00b3d97a9873371557d7b1f2ac5db7985e43sewardjstatic
6796e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardjUInt dis_xadd_G_E ( UChar sorb, Bool locked, Int sz, Int delta0,
6797e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                    Bool* decodeOK )
6798883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj{
6799883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   Int   len;
6800883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   UChar rm = getIByte(delta0);
6801c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
6802883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
6803883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   IRType ty    = szToITy(sz);
6804883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   IRTemp tmpd  = newTemp(ty);
6805883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   IRTemp tmpt0 = newTemp(ty);
6806883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   IRTemp tmpt1 = newTemp(ty);
6807883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
6808e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* There are 3 cases to consider:
6809e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6810c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      reg-reg: ignore any lock prefix,
6811c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj               generate 'naive' (non-atomic) sequence
6812e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6813e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      reg-mem, not locked: ignore any lock prefix, generate 'naive'
6814e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           (non-atomic) sequence
6815e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6816e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      reg-mem, locked: use IRCAS
6817e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   */
6818e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6819883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   if (epartIsReg(rm)) {
6820e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* case 1 */
6821c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      assign( tmpd,  getIReg(sz, eregOfRM(rm)));
6822c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6823c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6824c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj                           mkexpr(tmpd), mkexpr(tmpt0)) );
6825c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6826c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      putIReg(sz, eregOfRM(rm), mkexpr(tmpt1));
6827c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6828c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      DIP("xadd%c %s, %s\n",
6829c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj          nameISize(sz), nameIReg(sz,gregOfRM(rm)),
6830c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj          				 nameIReg(sz,eregOfRM(rm)));
6831c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      *decodeOK = True;
6832c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      return 1+delta0;
6833e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
6834e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   else if (!epartIsReg(rm) && !locked) {
6835e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* case 2 */
6836e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6837e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( tmpd,  loadLE(ty, mkexpr(addr)) );
6838e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6839e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6840e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           mkexpr(tmpd), mkexpr(tmpt0)) );
6841e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      storeLE( mkexpr(addr), mkexpr(tmpt1) );
6842e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6843e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6844883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      DIP("xadd%c %s, %s\n",
6845e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj          nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6846e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      *decodeOK = True;
6847e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      return len+delta0;
6848e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
6849e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   else if (!epartIsReg(rm) && locked) {
6850e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* case 3 */
6851883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6852883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      assign( tmpd,  loadLE(ty, mkexpr(addr)) );
6853883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6854e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6855e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           mkexpr(tmpd), mkexpr(tmpt0)) );
6856e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      casLE( mkexpr(addr), mkexpr(tmpd)/*expVal*/,
6857e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           mkexpr(tmpt1)/*newVal*/, guest_EIP_curr_instr );
68582a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6859883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6860883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      DIP("xadd%c %s, %s\n",
6861883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj          nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
68620092e0d63a749778959b481a734dcbb3fb299766sewardj      *decodeOK = True;
6863883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      return len+delta0;
6864883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   }
6865e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /*UNREACHED*/
6866e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   vassert(0);
6867883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj}
6868883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
6869b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj/* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
6870b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
68717df596b1e36840e2d74c90aa55589934add61ccfsewardjstatic
687252d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_mov_Ew_Sw ( UChar sorb, Int delta0 )
68737df596b1e36840e2d74c90aa55589934add61ccfsewardj{
6874b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   Int    len;
6875b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   IRTemp addr;
6876b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   UChar  rm  = getIByte(delta0);
6877b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   HChar  dis_buf[50];
68787df596b1e36840e2d74c90aa55589934add61ccfsewardj
68797df596b1e36840e2d74c90aa55589934add61ccfsewardj   if (epartIsReg(rm)) {
68807df596b1e36840e2d74c90aa55589934add61ccfsewardj      putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
68817df596b1e36840e2d74c90aa55589934add61ccfsewardj      DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
68827df596b1e36840e2d74c90aa55589934add61ccfsewardj      return 1+delta0;
6883b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   } else {
6884b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      addr = disAMode ( &len, sorb, delta0, dis_buf );
6885b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
6886b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
6887b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      return len+delta0;
68887df596b1e36840e2d74c90aa55589934add61ccfsewardj   }
68897df596b1e36840e2d74c90aa55589934add61ccfsewardj}
68907df596b1e36840e2d74c90aa55589934add61ccfsewardj
6891b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj/* Move 16 bits from G (a segment register) to Ew (ireg or mem).  If
6892b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   dst is ireg and sz==4, zero out top half of it.  */
6893b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
6894063f02f7e77ca024d24786bec402ca296a05bd6esewardjstatic
6895063f02f7e77ca024d24786bec402ca296a05bd6esewardjUInt dis_mov_Sw_Ew ( UChar sorb,
6896063f02f7e77ca024d24786bec402ca296a05bd6esewardj                     Int   sz,
689752d049186d07991237a825ec88aa7f1f303edb70sewardj                     Int   delta0 )
6898063f02f7e77ca024d24786bec402ca296a05bd6esewardj{
6899b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   Int    len;
6900b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   IRTemp addr;
6901b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   UChar  rm  = getIByte(delta0);
6902b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   HChar  dis_buf[50];
6903063f02f7e77ca024d24786bec402ca296a05bd6esewardj
6904063f02f7e77ca024d24786bec402ca296a05bd6esewardj   vassert(sz == 2 || sz == 4);
6905063f02f7e77ca024d24786bec402ca296a05bd6esewardj
6906063f02f7e77ca024d24786bec402ca296a05bd6esewardj   if (epartIsReg(rm)) {
6907063f02f7e77ca024d24786bec402ca296a05bd6esewardj      if (sz == 4)
6908063f02f7e77ca024d24786bec402ca296a05bd6esewardj         putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6909063f02f7e77ca024d24786bec402ca296a05bd6esewardj      else
6910063f02f7e77ca024d24786bec402ca296a05bd6esewardj         putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6911063f02f7e77ca024d24786bec402ca296a05bd6esewardj
6912063f02f7e77ca024d24786bec402ca296a05bd6esewardj      DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6913063f02f7e77ca024d24786bec402ca296a05bd6esewardj      return 1+delta0;
6914b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   } else {
6915b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      addr = disAMode ( &len, sorb, delta0, dis_buf );
6916b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
6917063f02f7e77ca024d24786bec402ca296a05bd6esewardj      DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
6918b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      return len+delta0;
6919063f02f7e77ca024d24786bec402ca296a05bd6esewardj   }
6920063f02f7e77ca024d24786bec402ca296a05bd6esewardj}
6921063f02f7e77ca024d24786bec402ca296a05bd6esewardj
6922063f02f7e77ca024d24786bec402ca296a05bd6esewardj
6923b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardjstatic
6924b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardjvoid dis_push_segreg ( UInt sreg, Int sz )
6925b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj{
6926b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    IRTemp t1 = newTemp(Ity_I16);
6927b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    IRTemp ta = newTemp(Ity_I32);
6928b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    vassert(sz == 2 || sz == 4);
6929b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
6930b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    assign( t1, getSReg(sreg) );
6931b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6932b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    putIReg(4, R_ESP, mkexpr(ta));
6933b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    storeLE( mkexpr(ta), mkexpr(t1) );
6934b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
69355c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj    DIP("push%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
6936b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj}
6937b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
6938b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardjstatic
6939b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardjvoid dis_pop_segreg ( UInt sreg, Int sz )
6940b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj{
6941b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    IRTemp t1 = newTemp(Ity_I16);
6942b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    IRTemp ta = newTemp(Ity_I32);
6943b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    vassert(sz == 2 || sz == 4);
6944b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
6945b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    assign( ta, getIReg(4, R_ESP) );
6946b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
6947b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
6948b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
6949b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    putSReg( sreg, mkexpr(t1) );
69505c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj    DIP("pop%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
6951b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj}
6952e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
6953e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjstatic
6954c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardjvoid dis_ret ( /*MOD*/DisResult* dres, UInt d32 )
6955e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj{
6956c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   IRTemp t1 = newTemp(Ity_I32);
6957c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   IRTemp t2 = newTemp(Ity_I32);
6958e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   assign(t1, getIReg(4,R_ESP));
6959e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6960e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
6961c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   jmp_treg(dres, Ijk_Ret, t2);
6962c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->whatNext == Dis_StopHere);
6963e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj}
6964e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
69654cb918d355cef4e7640d374346852db4556f3524sewardj/*------------------------------------------------------------*/
69664cb918d355cef4e7640d374346852db4556f3524sewardj/*--- SSE/SSE2/SSE3 helpers                                ---*/
69674cb918d355cef4e7640d374346852db4556f3524sewardj/*------------------------------------------------------------*/
6968c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
69699571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj/* Indicates whether the op requires a rounding-mode argument.  Note
69709571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   that this covers only vector floating point arithmetic ops, and
69719571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   omits the scalar ones that need rounding modes.  Note also that
69729571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   inconsistencies here will get picked up later by the IR sanity
69739571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   checker, so this isn't correctness-critical. */
69749571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardjstatic Bool requiresRMode ( IROp op )
69759571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj{
69769571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   switch (op) {
69779571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      /* 128 bit ops */
69789571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      case Iop_Add32Fx4: case Iop_Sub32Fx4:
69799571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      case Iop_Mul32Fx4: case Iop_Div32Fx4:
69809571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      case Iop_Add64Fx2: case Iop_Sub64Fx2:
69819571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      case Iop_Mul64Fx2: case Iop_Div64Fx2:
69829571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj         return True;
69839571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      default:
69849571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj         break;
69859571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   }
69869571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   return False;
69879571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj}
69889571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj
69899571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj
6990129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj/* Worker function; do not call directly.
6991129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   Handles full width G = G `op` E   and   G = (not G) `op` E.
6992129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj*/
6993129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
6994129b3d9da92af2ad2c58ffacb977aa5766211f08sewardjstatic UInt dis_SSE_E_to_G_all_wrk (
699552d049186d07991237a825ec88aa7f1f303edb70sewardj               UChar sorb, Int delta,
699655085f8680acc89d727e321f3b34cae1a8c4093aflorian               const HChar* opname, IROp op,
69971e6ad745ebafd0524da1da27a4b85524fa84f777sewardj               Bool   invertG
69981e6ad745ebafd0524da1da27a4b85524fa84f777sewardj            )
6999c9a43665879a03886b27a65b68af2a2c11b04f59sewardj{
70001e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   HChar   dis_buf[50];
70011e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   Int     alen;
70021e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   IRTemp  addr;
70031e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   UChar   rm = getIByte(delta);
70041e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   IRExpr* gpart
7005f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRM(rm)))
70061e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                : getXMMReg(gregOfRM(rm));
7007c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   if (epartIsReg(rm)) {
70089571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      putXMMReg(
70099571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj         gregOfRM(rm),
70109571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj         requiresRMode(op)
70119571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj            ? triop(op, get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
70129571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                        gpart,
70139571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                        getXMMReg(eregOfRM(rm)))
70149571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj            : binop(op, gpart,
70159571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                        getXMMReg(eregOfRM(rm)))
70169571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      );
7017c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      DIP("%s %s,%s\n", opname,
7018c9a43665879a03886b27a65b68af2a2c11b04f59sewardj                        nameXMMReg(eregOfRM(rm)),
7019c9a43665879a03886b27a65b68af2a2c11b04f59sewardj                        nameXMMReg(gregOfRM(rm)) );
7020c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      return delta+1;
7021c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   } else {
70221e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
70239571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      putXMMReg(
70249571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj         gregOfRM(rm),
70259571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj         requiresRMode(op)
70269571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj            ? triop(op, get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
70279571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                        gpart,
70289571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                        loadLE(Ity_V128, mkexpr(addr)))
70299571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj            : binop(op, gpart,
70309571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                        loadLE(Ity_V128, mkexpr(addr)))
70319571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      );
70321e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      DIP("%s %s,%s\n", opname,
70331e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                        dis_buf,
70341e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                        nameXMMReg(gregOfRM(rm)) );
70351e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      return delta+alen;
7036c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   }
7037c9a43665879a03886b27a65b68af2a2c11b04f59sewardj}
7038c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
7039129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
7040129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj/* All lanes SSE binary operation, G = G `op` E. */
7041129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
70421e6ad745ebafd0524da1da27a4b85524fa84f777sewardjstatic
704355085f8680acc89d727e321f3b34cae1a8c4093aflorianUInt dis_SSE_E_to_G_all ( UChar sorb, Int delta, const HChar* opname, IROp op )
70441e6ad745ebafd0524da1da27a4b85524fa84f777sewardj{
7045129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
70461e6ad745ebafd0524da1da27a4b85524fa84f777sewardj}
70471e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
7048129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj/* All lanes SSE binary operation, G = (not G) `op` E. */
7049129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
70501e6ad745ebafd0524da1da27a4b85524fa84f777sewardjstatic
705152d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_SSE_E_to_G_all_invG ( UChar sorb, Int delta,
705255085f8680acc89d727e321f3b34cae1a8c4093aflorian                               const HChar* opname, IROp op )
70531e6ad745ebafd0524da1da27a4b85524fa84f777sewardj{
7054129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
70551e6ad745ebafd0524da1da27a4b85524fa84f777sewardj}
70561e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
7057164f9275c465cd09ecd09276b8542282f5def250sewardj
7058129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
7059129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
706052d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt dis_SSE_E_to_G_lo32 ( UChar sorb, Int delta,
706155085f8680acc89d727e321f3b34cae1a8c4093aflorian                                  const HChar* opname, IROp op )
7062129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj{
7063129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   HChar   dis_buf[50];
7064129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   Int     alen;
7065129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   IRTemp  addr;
7066129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   UChar   rm = getIByte(delta);
7067129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   IRExpr* gpart = getXMMReg(gregOfRM(rm));
7068129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   if (epartIsReg(rm)) {
7069129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      putXMMReg( gregOfRM(rm),
7070129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                 binop(op, gpart,
7071129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                           getXMMReg(eregOfRM(rm))) );
7072129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      DIP("%s %s,%s\n", opname,
7073129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        nameXMMReg(eregOfRM(rm)),
7074129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        nameXMMReg(gregOfRM(rm)) );
7075129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      return delta+1;
7076129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   } else {
7077129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      /* We can only do a 32-bit memory read, so the upper 3/4 of the
7078129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj         E operand needs to be made simply of zeroes. */
7079129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      IRTemp epart = newTemp(Ity_V128);
7080129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
7081f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( epart, unop( Iop_32UtoV128,
7082129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                           loadLE(Ity_I32, mkexpr(addr))) );
7083129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      putXMMReg( gregOfRM(rm),
7084129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                 binop(op, gpart, mkexpr(epart)) );
7085129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      DIP("%s %s,%s\n", opname,
7086129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        dis_buf,
7087129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        nameXMMReg(gregOfRM(rm)) );
7088129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      return delta+alen;
7089129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   }
7090129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj}
7091129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
7092164f9275c465cd09ecd09276b8542282f5def250sewardj
7093636ad762e49597ef608323f27c7b8eb66962cd90sewardj/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
7094636ad762e49597ef608323f27c7b8eb66962cd90sewardj
709552d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt dis_SSE_E_to_G_lo64 ( UChar sorb, Int delta,
709655085f8680acc89d727e321f3b34cae1a8c4093aflorian                                  const HChar* opname, IROp op )
7097636ad762e49597ef608323f27c7b8eb66962cd90sewardj{
7098636ad762e49597ef608323f27c7b8eb66962cd90sewardj   HChar   dis_buf[50];
7099636ad762e49597ef608323f27c7b8eb66962cd90sewardj   Int     alen;
7100636ad762e49597ef608323f27c7b8eb66962cd90sewardj   IRTemp  addr;
7101636ad762e49597ef608323f27c7b8eb66962cd90sewardj   UChar   rm = getIByte(delta);
7102636ad762e49597ef608323f27c7b8eb66962cd90sewardj   IRExpr* gpart = getXMMReg(gregOfRM(rm));
7103636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (epartIsReg(rm)) {
7104636ad762e49597ef608323f27c7b8eb66962cd90sewardj      putXMMReg( gregOfRM(rm),
7105636ad762e49597ef608323f27c7b8eb66962cd90sewardj                 binop(op, gpart,
7106636ad762e49597ef608323f27c7b8eb66962cd90sewardj                           getXMMReg(eregOfRM(rm))) );
7107636ad762e49597ef608323f27c7b8eb66962cd90sewardj      DIP("%s %s,%s\n", opname,
7108636ad762e49597ef608323f27c7b8eb66962cd90sewardj                        nameXMMReg(eregOfRM(rm)),
7109636ad762e49597ef608323f27c7b8eb66962cd90sewardj                        nameXMMReg(gregOfRM(rm)) );
7110636ad762e49597ef608323f27c7b8eb66962cd90sewardj      return delta+1;
7111636ad762e49597ef608323f27c7b8eb66962cd90sewardj   } else {
7112636ad762e49597ef608323f27c7b8eb66962cd90sewardj      /* We can only do a 64-bit memory read, so the upper half of the
7113636ad762e49597ef608323f27c7b8eb66962cd90sewardj         E operand needs to be made simply of zeroes. */
7114636ad762e49597ef608323f27c7b8eb66962cd90sewardj      IRTemp epart = newTemp(Ity_V128);
7115636ad762e49597ef608323f27c7b8eb66962cd90sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
7116f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( epart, unop( Iop_64UtoV128,
7117636ad762e49597ef608323f27c7b8eb66962cd90sewardj                           loadLE(Ity_I64, mkexpr(addr))) );
7118636ad762e49597ef608323f27c7b8eb66962cd90sewardj      putXMMReg( gregOfRM(rm),
7119636ad762e49597ef608323f27c7b8eb66962cd90sewardj                 binop(op, gpart, mkexpr(epart)) );
7120636ad762e49597ef608323f27c7b8eb66962cd90sewardj      DIP("%s %s,%s\n", opname,
7121636ad762e49597ef608323f27c7b8eb66962cd90sewardj                        dis_buf,
7122636ad762e49597ef608323f27c7b8eb66962cd90sewardj                        nameXMMReg(gregOfRM(rm)) );
7123636ad762e49597ef608323f27c7b8eb66962cd90sewardj      return delta+alen;
7124636ad762e49597ef608323f27c7b8eb66962cd90sewardj   }
7125636ad762e49597ef608323f27c7b8eb66962cd90sewardj}
7126636ad762e49597ef608323f27c7b8eb66962cd90sewardj
7127164f9275c465cd09ecd09276b8542282f5def250sewardj
7128129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj/* All lanes unary SSE operation, G = op(E). */
7129129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
7130129b3d9da92af2ad2c58ffacb977aa5766211f08sewardjstatic UInt dis_SSE_E_to_G_unary_all (
713152d049186d07991237a825ec88aa7f1f303edb70sewardj               UChar sorb, Int delta,
713255085f8680acc89d727e321f3b34cae1a8c4093aflorian               const HChar* opname, IROp op
71330bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj            )
71340bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj{
71350bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   HChar   dis_buf[50];
71360bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   Int     alen;
71370bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   IRTemp  addr;
71380bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   UChar   rm = getIByte(delta);
71398bb1c9e03843a0a9d939279b738f280919bce8cbsewardj   // Sqrt32Fx4 and Sqrt64Fx2 take a rounding mode, which is faked
71408bb1c9e03843a0a9d939279b738f280919bce8cbsewardj   // up in the usual way.
71418bb1c9e03843a0a9d939279b738f280919bce8cbsewardj   Bool needsIRRM = op == Iop_Sqrt32Fx4 || op == Iop_Sqrt64Fx2;
71420bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   if (epartIsReg(rm)) {
71438bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      IRExpr* src = getXMMReg(eregOfRM(rm));
71448bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      /* XXXROUNDINGFIXME */
71458bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      IRExpr* res = needsIRRM ? binop(op, get_FAKE_roundingmode(), src)
71468bb1c9e03843a0a9d939279b738f280919bce8cbsewardj                              : unop(op, src);
71478bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      putXMMReg( gregOfRM(rm), res );
71480bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      DIP("%s %s,%s\n", opname,
71490bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj                        nameXMMReg(eregOfRM(rm)),
71500bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj                        nameXMMReg(gregOfRM(rm)) );
71510bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      return delta+1;
71520bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   } else {
71530bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
71548bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      IRExpr* src = loadLE(Ity_V128, mkexpr(addr));
71558bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      /* XXXROUNDINGFIXME */
71568bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      IRExpr* res = needsIRRM ? binop(op, get_FAKE_roundingmode(), src)
71578bb1c9e03843a0a9d939279b738f280919bce8cbsewardj                              : unop(op, src);
71588bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      putXMMReg( gregOfRM(rm), res );
71590bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      DIP("%s %s,%s\n", opname,
71600bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj                        dis_buf,
71610bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj                        nameXMMReg(gregOfRM(rm)) );
71620bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      return delta+alen;
71630bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
71640bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj}
71650bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
7166164f9275c465cd09ecd09276b8542282f5def250sewardj
7167129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
71680bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
7169129b3d9da92af2ad2c58ffacb977aa5766211f08sewardjstatic UInt dis_SSE_E_to_G_unary_lo32 (
717052d049186d07991237a825ec88aa7f1f303edb70sewardj               UChar sorb, Int delta,
717155085f8680acc89d727e321f3b34cae1a8c4093aflorian               const HChar* opname, IROp op
7172129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj            )
7173129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj{
7174129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   /* First we need to get the old G value and patch the low 32 bits
7175129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      of the E operand into it.  Then apply op and write back to G. */
7176129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   HChar   dis_buf[50];
7177129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   Int     alen;
7178129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   IRTemp  addr;
7179129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   UChar   rm = getIByte(delta);
7180129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   IRTemp  oldG0 = newTemp(Ity_V128);
7181129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   IRTemp  oldG1 = newTemp(Ity_V128);
7182129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
7183129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   assign( oldG0, getXMMReg(gregOfRM(rm)) );
7184129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
7185129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   if (epartIsReg(rm)) {
7186129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      assign( oldG1,
7187f0c1c58d6e47608ce166058997f795f1d7d45127sewardj              binop( Iop_SetV128lo32,
7188129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                     mkexpr(oldG0),
718935579be3fac7bf13b1e2bf39470475aa5332b6d7sewardj                     getXMMRegLane32(eregOfRM(rm), 0)) );
7190129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7191129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      DIP("%s %s,%s\n", opname,
7192129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        nameXMMReg(eregOfRM(rm)),
7193129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        nameXMMReg(gregOfRM(rm)) );
7194129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      return delta+1;
7195129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   } else {
7196129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
7197129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      assign( oldG1,
7198f0c1c58d6e47608ce166058997f795f1d7d45127sewardj              binop( Iop_SetV128lo32,
7199129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                     mkexpr(oldG0),
7200129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                     loadLE(Ity_I32, mkexpr(addr)) ));
7201129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7202129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      DIP("%s %s,%s\n", opname,
7203129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        dis_buf,
7204129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        nameXMMReg(gregOfRM(rm)) );
7205129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      return delta+alen;
7206129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   }
7207129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj}
7208129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
7209164f9275c465cd09ecd09276b8542282f5def250sewardj
7210008754b1685e50d117f9c982ddeeafbaca151bfesewardj/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7211008754b1685e50d117f9c982ddeeafbaca151bfesewardj
7212008754b1685e50d117f9c982ddeeafbaca151bfesewardjstatic UInt dis_SSE_E_to_G_unary_lo64 (
721352d049186d07991237a825ec88aa7f1f303edb70sewardj               UChar sorb, Int delta,
721455085f8680acc89d727e321f3b34cae1a8c4093aflorian               const HChar* opname, IROp op
7215008754b1685e50d117f9c982ddeeafbaca151bfesewardj            )
7216008754b1685e50d117f9c982ddeeafbaca151bfesewardj{
7217008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* First we need to get the old G value and patch the low 64 bits
7218008754b1685e50d117f9c982ddeeafbaca151bfesewardj      of the E operand into it.  Then apply op and write back to G. */
7219008754b1685e50d117f9c982ddeeafbaca151bfesewardj   HChar   dis_buf[50];
7220008754b1685e50d117f9c982ddeeafbaca151bfesewardj   Int     alen;
7221008754b1685e50d117f9c982ddeeafbaca151bfesewardj   IRTemp  addr;
7222008754b1685e50d117f9c982ddeeafbaca151bfesewardj   UChar   rm = getIByte(delta);
7223008754b1685e50d117f9c982ddeeafbaca151bfesewardj   IRTemp  oldG0 = newTemp(Ity_V128);
7224008754b1685e50d117f9c982ddeeafbaca151bfesewardj   IRTemp  oldG1 = newTemp(Ity_V128);
7225008754b1685e50d117f9c982ddeeafbaca151bfesewardj
7226008754b1685e50d117f9c982ddeeafbaca151bfesewardj   assign( oldG0, getXMMReg(gregOfRM(rm)) );
7227008754b1685e50d117f9c982ddeeafbaca151bfesewardj
7228008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (epartIsReg(rm)) {
7229008754b1685e50d117f9c982ddeeafbaca151bfesewardj      assign( oldG1,
7230f0c1c58d6e47608ce166058997f795f1d7d45127sewardj              binop( Iop_SetV128lo64,
7231008754b1685e50d117f9c982ddeeafbaca151bfesewardj                     mkexpr(oldG0),
7232008754b1685e50d117f9c982ddeeafbaca151bfesewardj                     getXMMRegLane64(eregOfRM(rm), 0)) );
7233008754b1685e50d117f9c982ddeeafbaca151bfesewardj      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7234008754b1685e50d117f9c982ddeeafbaca151bfesewardj      DIP("%s %s,%s\n", opname,
7235008754b1685e50d117f9c982ddeeafbaca151bfesewardj                        nameXMMReg(eregOfRM(rm)),
7236008754b1685e50d117f9c982ddeeafbaca151bfesewardj                        nameXMMReg(gregOfRM(rm)) );
7237008754b1685e50d117f9c982ddeeafbaca151bfesewardj      return delta+1;
7238008754b1685e50d117f9c982ddeeafbaca151bfesewardj   } else {
7239008754b1685e50d117f9c982ddeeafbaca151bfesewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
7240008754b1685e50d117f9c982ddeeafbaca151bfesewardj      assign( oldG1,
7241f0c1c58d6e47608ce166058997f795f1d7d45127sewardj              binop( Iop_SetV128lo64,
7242008754b1685e50d117f9c982ddeeafbaca151bfesewardj                     mkexpr(oldG0),
7243008754b1685e50d117f9c982ddeeafbaca151bfesewardj                     loadLE(Ity_I64, mkexpr(addr)) ));
7244008754b1685e50d117f9c982ddeeafbaca151bfesewardj      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7245008754b1685e50d117f9c982ddeeafbaca151bfesewardj      DIP("%s %s,%s\n", opname,
7246008754b1685e50d117f9c982ddeeafbaca151bfesewardj                        dis_buf,
7247008754b1685e50d117f9c982ddeeafbaca151bfesewardj                        nameXMMReg(gregOfRM(rm)) );
7248008754b1685e50d117f9c982ddeeafbaca151bfesewardj      return delta+alen;
7249008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
7250008754b1685e50d117f9c982ddeeafbaca151bfesewardj}
7251008754b1685e50d117f9c982ddeeafbaca151bfesewardj
7252164f9275c465cd09ecd09276b8542282f5def250sewardj
7253164f9275c465cd09ecd09276b8542282f5def250sewardj/* SSE integer binary operation:
7254164f9275c465cd09ecd09276b8542282f5def250sewardj      G = G `op` E   (eLeft == False)
7255164f9275c465cd09ecd09276b8542282f5def250sewardj      G = E `op` G   (eLeft == True)
7256164f9275c465cd09ecd09276b8542282f5def250sewardj*/
7257164f9275c465cd09ecd09276b8542282f5def250sewardjstatic UInt dis_SSEint_E_to_G(
725852d049186d07991237a825ec88aa7f1f303edb70sewardj               UChar sorb, Int delta,
725955085f8680acc89d727e321f3b34cae1a8c4093aflorian               const HChar* opname, IROp op,
7260164f9275c465cd09ecd09276b8542282f5def250sewardj               Bool   eLeft
7261164f9275c465cd09ecd09276b8542282f5def250sewardj            )
7262164f9275c465cd09ecd09276b8542282f5def250sewardj{
7263164f9275c465cd09ecd09276b8542282f5def250sewardj   HChar   dis_buf[50];
7264164f9275c465cd09ecd09276b8542282f5def250sewardj   Int     alen;
7265164f9275c465cd09ecd09276b8542282f5def250sewardj   IRTemp  addr;
7266164f9275c465cd09ecd09276b8542282f5def250sewardj   UChar   rm = getIByte(delta);
7267164f9275c465cd09ecd09276b8542282f5def250sewardj   IRExpr* gpart = getXMMReg(gregOfRM(rm));
7268164f9275c465cd09ecd09276b8542282f5def250sewardj   IRExpr* epart = NULL;
7269164f9275c465cd09ecd09276b8542282f5def250sewardj   if (epartIsReg(rm)) {
7270164f9275c465cd09ecd09276b8542282f5def250sewardj      epart = getXMMReg(eregOfRM(rm));
7271164f9275c465cd09ecd09276b8542282f5def250sewardj      DIP("%s %s,%s\n", opname,
7272164f9275c465cd09ecd09276b8542282f5def250sewardj                        nameXMMReg(eregOfRM(rm)),
7273164f9275c465cd09ecd09276b8542282f5def250sewardj                        nameXMMReg(gregOfRM(rm)) );
7274164f9275c465cd09ecd09276b8542282f5def250sewardj      delta += 1;
7275164f9275c465cd09ecd09276b8542282f5def250sewardj   } else {
7276164f9275c465cd09ecd09276b8542282f5def250sewardj      addr  = disAMode ( &alen, sorb, delta, dis_buf );
7277164f9275c465cd09ecd09276b8542282f5def250sewardj      epart = loadLE(Ity_V128, mkexpr(addr));
7278164f9275c465cd09ecd09276b8542282f5def250sewardj      DIP("%s %s,%s\n", opname,
7279164f9275c465cd09ecd09276b8542282f5def250sewardj                        dis_buf,
7280164f9275c465cd09ecd09276b8542282f5def250sewardj                        nameXMMReg(gregOfRM(rm)) );
7281164f9275c465cd09ecd09276b8542282f5def250sewardj      delta += alen;
7282164f9275c465cd09ecd09276b8542282f5def250sewardj   }
7283164f9275c465cd09ecd09276b8542282f5def250sewardj   putXMMReg( gregOfRM(rm),
7284164f9275c465cd09ecd09276b8542282f5def250sewardj              eLeft ? binop(op, epart, gpart)
7285164f9275c465cd09ecd09276b8542282f5def250sewardj	            : binop(op, gpart, epart) );
7286164f9275c465cd09ecd09276b8542282f5def250sewardj   return delta;
7287164f9275c465cd09ecd09276b8542282f5def250sewardj}
7288164f9275c465cd09ecd09276b8542282f5def250sewardj
7289164f9275c465cd09ecd09276b8542282f5def250sewardj
7290fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj/* Helper for doing SSE FP comparisons. */
72910bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
72921e6ad745ebafd0524da1da27a4b85524fa84f777sewardjstatic void findSSECmpOp ( Bool* needNot, IROp* op,
72931e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                           Int imm8, Bool all_lanes, Int sz )
72941e6ad745ebafd0524da1da27a4b85524fa84f777sewardj{
72951e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   imm8 &= 7;
72961e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   *needNot = False;
72971e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   *op      = Iop_INVALID;
72981e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   if (imm8 >= 4) {
72991e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      *needNot = True;
73001e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      imm8 -= 4;
73011e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
73021e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
73031e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   if (sz == 4 && all_lanes) {
73041e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      switch (imm8) {
73051e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 0: *op = Iop_CmpEQ32Fx4; return;
73061e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 1: *op = Iop_CmpLT32Fx4; return;
73071e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 2: *op = Iop_CmpLE32Fx4; return;
73081e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 3: *op = Iop_CmpUN32Fx4; return;
73091e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         default: break;
73101e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      }
73111e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
73121e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   if (sz == 4 && !all_lanes) {
73131e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      switch (imm8) {
73141e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 0: *op = Iop_CmpEQ32F0x4; return;
73151e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 1: *op = Iop_CmpLT32F0x4; return;
73161e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 2: *op = Iop_CmpLE32F0x4; return;
73171e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 3: *op = Iop_CmpUN32F0x4; return;
73181e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         default: break;
73191e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      }
73201e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
7321fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 8 && all_lanes) {
7322fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      switch (imm8) {
7323fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 0: *op = Iop_CmpEQ64Fx2; return;
7324fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 1: *op = Iop_CmpLT64Fx2; return;
7325fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 2: *op = Iop_CmpLE64Fx2; return;
7326fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 3: *op = Iop_CmpUN64Fx2; return;
7327fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         default: break;
7328fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
7329fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
7330fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 8 && !all_lanes) {
7331fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      switch (imm8) {
7332fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 0: *op = Iop_CmpEQ64F0x2; return;
7333fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 1: *op = Iop_CmpLT64F0x2; return;
7334fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 2: *op = Iop_CmpLE64F0x2; return;
7335fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 3: *op = Iop_CmpUN64F0x2; return;
7336fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         default: break;
7337fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
73381e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
73391e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   vpanic("findSSECmpOp(x86,guest)");
73401e6ad745ebafd0524da1da27a4b85524fa84f777sewardj}
73411e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
734233c69e5236ab884bd8ce9491432d4d00a6b95389sewardj/* Handles SSE 32F/64F comparisons. */
7343129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
734452d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt dis_SSEcmp_E_to_G ( UChar sorb, Int delta,
734555085f8680acc89d727e321f3b34cae1a8c4093aflorian				const HChar* opname, Bool all_lanes, Int sz )
73461e6ad745ebafd0524da1da27a4b85524fa84f777sewardj{
73471e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   HChar   dis_buf[50];
73481e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   Int     alen, imm8;
73491e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   IRTemp  addr;
73501e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   Bool    needNot = False;
73511e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   IROp    op      = Iop_INVALID;
73521e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   IRTemp  plain   = newTemp(Ity_V128);
73531e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   UChar   rm      = getIByte(delta);
73541e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   UShort  mask    = 0;
73551e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   vassert(sz == 4 || sz == 8);
73561e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   if (epartIsReg(rm)) {
73571e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      imm8 = getIByte(delta+1);
73581e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
73591e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
73601e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                               getXMMReg(eregOfRM(rm))) );
73611e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      delta += 2;
73621e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      DIP("%s $%d,%s,%s\n", opname,
7363b173774421d015736c2316b5e6e998e7de545a5cflorian                            imm8,
73641e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                            nameXMMReg(eregOfRM(rm)),
73651e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                            nameXMMReg(gregOfRM(rm)) );
73661e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   } else {
73671e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
73681e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      imm8 = getIByte(delta+alen);
73691e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
737033c69e5236ab884bd8ce9491432d4d00a6b95389sewardj      assign( plain,
737133c69e5236ab884bd8ce9491432d4d00a6b95389sewardj              binop(
737233c69e5236ab884bd8ce9491432d4d00a6b95389sewardj                 op,
737333c69e5236ab884bd8ce9491432d4d00a6b95389sewardj                 getXMMReg(gregOfRM(rm)),
737433c69e5236ab884bd8ce9491432d4d00a6b95389sewardj                   all_lanes  ? loadLE(Ity_V128, mkexpr(addr))
737533c69e5236ab884bd8ce9491432d4d00a6b95389sewardj                 : sz == 8    ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
737633c69e5236ab884bd8ce9491432d4d00a6b95389sewardj                 : /*sz==4*/    unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
737733c69e5236ab884bd8ce9491432d4d00a6b95389sewardj             )
737833c69e5236ab884bd8ce9491432d4d00a6b95389sewardj      );
73791e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      delta += alen+1;
73801e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      DIP("%s $%d,%s,%s\n", opname,
7381b173774421d015736c2316b5e6e998e7de545a5cflorian                            imm8,
73821e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                            dis_buf,
73831e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                            nameXMMReg(gregOfRM(rm)) );
73841e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
73851e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
73862e38386d2f5902feed6ec276c2c2292a137717b9sewardj   if (needNot && all_lanes) {
73872e38386d2f5902feed6ec276c2c2292a137717b9sewardj      putXMMReg( gregOfRM(rm),
7388f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                 unop(Iop_NotV128, mkexpr(plain)) );
73892e38386d2f5902feed6ec276c2c2292a137717b9sewardj   }
73902e38386d2f5902feed6ec276c2c2292a137717b9sewardj   else
73912e38386d2f5902feed6ec276c2c2292a137717b9sewardj   if (needNot && !all_lanes) {
73929b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj      mask = toUShort( sz==4 ? 0x000F : 0x00FF );
73932e38386d2f5902feed6ec276c2c2292a137717b9sewardj      putXMMReg( gregOfRM(rm),
7394f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
73952e38386d2f5902feed6ec276c2c2292a137717b9sewardj   }
73962e38386d2f5902feed6ec276c2c2292a137717b9sewardj   else {
73972e38386d2f5902feed6ec276c2c2292a137717b9sewardj      putXMMReg( gregOfRM(rm), mkexpr(plain) );
73982e38386d2f5902feed6ec276c2c2292a137717b9sewardj   }
73991e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
74001e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   return delta;
74011e6ad745ebafd0524da1da27a4b85524fa84f777sewardj}
74021e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
7403b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7404b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj/* Vector by scalar shift of G by the amount specified at the bottom
7405b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   of E. */
7406b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
740752d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt dis_SSE_shiftG_byE ( UChar sorb, Int delta,
740855085f8680acc89d727e321f3b34cae1a8c4093aflorian                                 const HChar* opname, IROp op )
7409b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj{
7410b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   HChar   dis_buf[50];
7411b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   Int     alen, size;
7412b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp  addr;
7413b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   Bool    shl, shr, sar;
7414b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   UChar   rm   = getIByte(delta);
7415b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp  g0   = newTemp(Ity_V128);
7416b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp  g1   = newTemp(Ity_V128);
7417b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp  amt  = newTemp(Ity_I32);
7418b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp  amt8 = newTemp(Ity_I8);
7419b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (epartIsReg(rm)) {
7420b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
7421b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      DIP("%s %s,%s\n", opname,
7422b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                        nameXMMReg(eregOfRM(rm)),
7423b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                        nameXMMReg(gregOfRM(rm)) );
7424b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta++;
7425b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   } else {
7426b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
7427b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
7428b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      DIP("%s %s,%s\n", opname,
7429b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                        dis_buf,
7430b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                        nameXMMReg(gregOfRM(rm)) );
7431b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta += alen;
7432b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
7433b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( g0,   getXMMReg(gregOfRM(rm)) );
7434b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
7435b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7436b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   shl = shr = sar = False;
7437b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   size = 0;
7438b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   switch (op) {
7439b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShlN16x8: shl = True; size = 32; break;
7440b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShlN32x4: shl = True; size = 32; break;
7441b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShlN64x2: shl = True; size = 64; break;
7442b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_SarN16x8: sar = True; size = 16; break;
7443b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_SarN32x4: sar = True; size = 32; break;
7444b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShrN16x8: shr = True; size = 16; break;
7445b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShrN32x4: shr = True; size = 32; break;
7446b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShrN64x2: shr = True; size = 64; break;
7447b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      default: vassert(0);
7448b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
7449b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7450b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (shl || shr) {
7451b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj     assign(
7452b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj        g1,
745399dd03e04a6914d90d5fee727d61d76905334becflorian        IRExpr_ITE(
7454009230b9758291b594e60d7c0243a73d53e81854sewardj           binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
745599dd03e04a6914d90d5fee727d61d76905334becflorian           binop(op, mkexpr(g0), mkexpr(amt8)),
745699dd03e04a6914d90d5fee727d61d76905334becflorian           mkV128(0x0000)
7457b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj        )
7458b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj     );
7459b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   } else
7460b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sar) {
7461b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj     assign(
7462b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj        g1,
746399dd03e04a6914d90d5fee727d61d76905334becflorian        IRExpr_ITE(
7464009230b9758291b594e60d7c0243a73d53e81854sewardj           binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
746599dd03e04a6914d90d5fee727d61d76905334becflorian           binop(op, mkexpr(g0), mkexpr(amt8)),
746699dd03e04a6914d90d5fee727d61d76905334becflorian           binop(op, mkexpr(g0), mkU8(size-1))
7467b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj        )
7468b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj     );
7469b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   } else {
7470ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      /*NOTREACHED*/
7471b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      vassert(0);
7472b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
7473b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7474b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   putXMMReg( gregOfRM(rm), mkexpr(g1) );
7475b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   return delta;
7476b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj}
7477b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7478b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7479b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj/* Vector by scalar shift of E by an immediate byte. */
7480b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
748138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardjstatic
748255085f8680acc89d727e321f3b34cae1a8c4093aflorianUInt dis_SSE_shiftE_imm ( Int delta, const HChar* opname, IROp op )
7483b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj{
7484b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   Bool    shl, shr, sar;
7485b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   UChar   rm   = getIByte(delta);
748638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  e0   = newTemp(Ity_V128);
748738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  e1   = newTemp(Ity_V128);
7488b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   UChar   amt, size;
7489b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   vassert(epartIsReg(rm));
7490b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   vassert(gregOfRM(rm) == 2
7491b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj           || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
74922d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj   amt = getIByte(delta+1);
7493b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   delta += 2;
7494b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   DIP("%s $%d,%s\n", opname,
7495b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                      (Int)amt,
7496b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                      nameXMMReg(eregOfRM(rm)) );
749738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   assign( e0, getXMMReg(eregOfRM(rm)) );
7498b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7499b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   shl = shr = sar = False;
7500b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   size = 0;
7501b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   switch (op) {
7502b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShlN16x8: shl = True; size = 16; break;
7503b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShlN32x4: shl = True; size = 32; break;
7504b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShlN64x2: shl = True; size = 64; break;
7505b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_SarN16x8: sar = True; size = 16; break;
7506b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_SarN32x4: sar = True; size = 32; break;
7507b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShrN16x8: shr = True; size = 16; break;
7508b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShrN32x4: shr = True; size = 32; break;
7509b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShrN64x2: shr = True; size = 64; break;
7510b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      default: vassert(0);
7511b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
7512b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7513b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (shl || shr) {
7514ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      assign( e1, amt >= size
7515ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     ? mkV128(0x0000)
7516ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     : binop(op, mkexpr(e0), mkU8(amt))
7517ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      );
7518b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   } else
7519b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sar) {
7520ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      assign( e1, amt >= size
7521ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     ? binop(op, mkexpr(e0), mkU8(size-1))
7522ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     : binop(op, mkexpr(e0), mkU8(amt))
7523ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      );
7524b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   } else {
7525ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      /*NOTREACHED*/
7526b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      vassert(0);
7527b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
7528b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
752938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   putXMMReg( eregOfRM(rm), mkexpr(e1) );
7530b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   return delta;
7531b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj}
7532b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7533b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7534c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj/* Get the current SSE rounding mode. */
7535c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
75364cb918d355cef4e7640d374346852db4556f3524sewardjstatic IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
75374cb918d355cef4e7640d374346852db4556f3524sewardj{
75384cb918d355cef4e7640d374346852db4556f3524sewardj   return binop( Iop_And32,
75394cb918d355cef4e7640d374346852db4556f3524sewardj                 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
75404cb918d355cef4e7640d374346852db4556f3524sewardj                 mkU32(3) );
75414cb918d355cef4e7640d374346852db4556f3524sewardj}
75424cb918d355cef4e7640d374346852db4556f3524sewardj
7543636ad762e49597ef608323f27c7b8eb66962cd90sewardjstatic void put_sse_roundingmode ( IRExpr* sseround )
7544636ad762e49597ef608323f27c7b8eb66962cd90sewardj{
7545dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv, sseround) == Ity_I32);
7546636ad762e49597ef608323f27c7b8eb66962cd90sewardj   stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
7547636ad762e49597ef608323f27c7b8eb66962cd90sewardj}
7548636ad762e49597ef608323f27c7b8eb66962cd90sewardj
7549c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj/* Break a 128-bit value up into four 32-bit ints. */
7550c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
7551c1e7dfc9370ee70f7e9f52294c764d4233619927sewardjstatic void breakup128to32s ( IRTemp t128,
7552c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj			      /*OUTs*/
7553c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                              IRTemp* t3, IRTemp* t2,
7554c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                              IRTemp* t1, IRTemp* t0 )
7555c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj{
7556c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   IRTemp hi64 = newTemp(Ity_I64);
7557c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   IRTemp lo64 = newTemp(Ity_I64);
7558f0c1c58d6e47608ce166058997f795f1d7d45127sewardj   assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
7559f0c1c58d6e47608ce166058997f795f1d7d45127sewardj   assign( lo64, unop(Iop_V128to64,   mkexpr(t128)) );
7560c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
7561c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   vassert(t0 && *t0 == IRTemp_INVALID);
7562c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   vassert(t1 && *t1 == IRTemp_INVALID);
7563c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   vassert(t2 && *t2 == IRTemp_INVALID);
7564c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   vassert(t3 && *t3 == IRTemp_INVALID);
7565c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
7566c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   *t0 = newTemp(Ity_I32);
7567c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   *t1 = newTemp(Ity_I32);
7568c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   *t2 = newTemp(Ity_I32);
7569c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   *t3 = newTemp(Ity_I32);
7570c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   assign( *t0, unop(Iop_64to32,   mkexpr(lo64)) );
7571c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
7572c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   assign( *t2, unop(Iop_64to32,   mkexpr(hi64)) );
7573c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
7574c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj}
7575c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
7576c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj/* Construct a 128-bit value from four 32-bit ints. */
7577c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
7578c1e7dfc9370ee70f7e9f52294c764d4233619927sewardjstatic IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
7579c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                              IRTemp t1, IRTemp t0 )
7580c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj{
7581c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   return
7582f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      binop( Iop_64HLtoV128,
7583c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj             binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
7584c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj             binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
7585c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   );
7586c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj}
7587c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
7588b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj/* Break a 64-bit value up into four 16-bit ints. */
7589b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7590b9fa69b4047ef2a1fd822bab909437c920b9c297sewardjstatic void breakup64to16s ( IRTemp t64,
7591b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                             /*OUTs*/
7592b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                             IRTemp* t3, IRTemp* t2,
7593b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                             IRTemp* t1, IRTemp* t0 )
7594b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj{
7595b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp hi32 = newTemp(Ity_I32);
7596b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp lo32 = newTemp(Ity_I32);
7597b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
7598b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( lo32, unop(Iop_64to32,   mkexpr(t64)) );
7599b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7600b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   vassert(t0 && *t0 == IRTemp_INVALID);
7601b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   vassert(t1 && *t1 == IRTemp_INVALID);
7602b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   vassert(t2 && *t2 == IRTemp_INVALID);
7603b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   vassert(t3 && *t3 == IRTemp_INVALID);
7604b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7605b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   *t0 = newTemp(Ity_I16);
7606b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   *t1 = newTemp(Ity_I16);
7607b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   *t2 = newTemp(Ity_I16);
7608b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   *t3 = newTemp(Ity_I16);
7609b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( *t0, unop(Iop_32to16,   mkexpr(lo32)) );
7610b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
7611b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( *t2, unop(Iop_32to16,   mkexpr(hi32)) );
7612b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
7613b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj}
7614b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7615b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj/* Construct a 64-bit value from four 16-bit ints. */
7616b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7617b9fa69b4047ef2a1fd822bab909437c920b9c297sewardjstatic IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
7618b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                             IRTemp t1, IRTemp t0 )
7619b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj{
7620b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   return
7621b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      binop( Iop_32HLto64,
7622b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj             binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7623b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj             binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7624b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   );
7625b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj}
7626b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
76270e9a0f551e190b475150dcd6bc4500033eb05338sewardj/* Generate IR to set the guest %EFLAGS from the pushfl-format image
76280e9a0f551e190b475150dcd6bc4500033eb05338sewardj   in the given 32-bit temporary.  The flags that are set are: O S Z A
76290e9a0f551e190b475150dcd6bc4500033eb05338sewardj   C P D ID AC.
76300e9a0f551e190b475150dcd6bc4500033eb05338sewardj
76310e9a0f551e190b475150dcd6bc4500033eb05338sewardj   In all cases, code to set AC is generated.  However, VEX actually
76320e9a0f551e190b475150dcd6bc4500033eb05338sewardj   ignores the AC value and so can optionally emit an emulation
76330e9a0f551e190b475150dcd6bc4500033eb05338sewardj   warning when it is enabled.  In this routine, an emulation warning
76340e9a0f551e190b475150dcd6bc4500033eb05338sewardj   is only emitted if emit_AC_emwarn is True, in which case
76350e9a0f551e190b475150dcd6bc4500033eb05338sewardj   next_insn_EIP must be correct (this allows for correct code
76360e9a0f551e190b475150dcd6bc4500033eb05338sewardj   generation for popfl/popfw).  If emit_AC_emwarn is False,
76370e9a0f551e190b475150dcd6bc4500033eb05338sewardj   next_insn_EIP is unimportant (this allows for easy if kludgey code
76380e9a0f551e190b475150dcd6bc4500033eb05338sewardj   generation for IRET.) */
76390e9a0f551e190b475150dcd6bc4500033eb05338sewardj
76400e9a0f551e190b475150dcd6bc4500033eb05338sewardjstatic
76410e9a0f551e190b475150dcd6bc4500033eb05338sewardjvoid set_EFLAGS_from_value ( IRTemp t1,
76420e9a0f551e190b475150dcd6bc4500033eb05338sewardj                             Bool   emit_AC_emwarn,
76430e9a0f551e190b475150dcd6bc4500033eb05338sewardj                             Addr32 next_insn_EIP )
76440e9a0f551e190b475150dcd6bc4500033eb05338sewardj{
76450e9a0f551e190b475150dcd6bc4500033eb05338sewardj   vassert(typeOfIRTemp(irsb->tyenv,t1) == Ity_I32);
76460e9a0f551e190b475150dcd6bc4500033eb05338sewardj
76470e9a0f551e190b475150dcd6bc4500033eb05338sewardj   /* t1 is the flag word.  Mask out everything except OSZACP and set
76480e9a0f551e190b475150dcd6bc4500033eb05338sewardj      the flags thunk to X86G_CC_OP_COPY. */
76490e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
76500e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
76510e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put( OFFB_CC_DEP1,
76520e9a0f551e190b475150dcd6bc4500033eb05338sewardj                     binop(Iop_And32,
76530e9a0f551e190b475150dcd6bc4500033eb05338sewardj                           mkexpr(t1),
76540e9a0f551e190b475150dcd6bc4500033eb05338sewardj                           mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
76550e9a0f551e190b475150dcd6bc4500033eb05338sewardj                                  | X86G_CC_MASK_A | X86G_CC_MASK_Z
76560e9a0f551e190b475150dcd6bc4500033eb05338sewardj                                  | X86G_CC_MASK_S| X86G_CC_MASK_O )
76570e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          )
76580e9a0f551e190b475150dcd6bc4500033eb05338sewardj                    )
76590e9a0f551e190b475150dcd6bc4500033eb05338sewardj       );
76600e9a0f551e190b475150dcd6bc4500033eb05338sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
76610e9a0f551e190b475150dcd6bc4500033eb05338sewardj      elimination of previous stores to this field work better. */
76620e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
76630e9a0f551e190b475150dcd6bc4500033eb05338sewardj
76640e9a0f551e190b475150dcd6bc4500033eb05338sewardj   /* Also need to set the D flag, which is held in bit 10 of t1.
76650e9a0f551e190b475150dcd6bc4500033eb05338sewardj      If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
76660e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put(
76670e9a0f551e190b475150dcd6bc4500033eb05338sewardj            OFFB_DFLAG,
766899dd03e04a6914d90d5fee727d61d76905334becflorian            IRExpr_ITE(
7669009230b9758291b594e60d7c0243a73d53e81854sewardj               unop(Iop_32to1,
76700e9a0f551e190b475150dcd6bc4500033eb05338sewardj                    binop(Iop_And32,
76710e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
76720e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          mkU32(1))),
767399dd03e04a6914d90d5fee727d61d76905334becflorian               mkU32(0xFFFFFFFF),
767499dd03e04a6914d90d5fee727d61d76905334becflorian               mkU32(1)))
76750e9a0f551e190b475150dcd6bc4500033eb05338sewardj       );
76760e9a0f551e190b475150dcd6bc4500033eb05338sewardj
76770e9a0f551e190b475150dcd6bc4500033eb05338sewardj   /* Set the ID flag */
76780e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put(
76790e9a0f551e190b475150dcd6bc4500033eb05338sewardj            OFFB_IDFLAG,
768099dd03e04a6914d90d5fee727d61d76905334becflorian            IRExpr_ITE(
7681009230b9758291b594e60d7c0243a73d53e81854sewardj               unop(Iop_32to1,
76820e9a0f551e190b475150dcd6bc4500033eb05338sewardj                    binop(Iop_And32,
76830e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
76840e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          mkU32(1))),
768599dd03e04a6914d90d5fee727d61d76905334becflorian               mkU32(1),
768699dd03e04a6914d90d5fee727d61d76905334becflorian               mkU32(0)))
76870e9a0f551e190b475150dcd6bc4500033eb05338sewardj       );
76880e9a0f551e190b475150dcd6bc4500033eb05338sewardj
76890e9a0f551e190b475150dcd6bc4500033eb05338sewardj   /* And set the AC flag.  If setting it 1 to, possibly emit an
76900e9a0f551e190b475150dcd6bc4500033eb05338sewardj      emulation warning. */
76910e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put(
76920e9a0f551e190b475150dcd6bc4500033eb05338sewardj            OFFB_ACFLAG,
769399dd03e04a6914d90d5fee727d61d76905334becflorian            IRExpr_ITE(
7694009230b9758291b594e60d7c0243a73d53e81854sewardj               unop(Iop_32to1,
76950e9a0f551e190b475150dcd6bc4500033eb05338sewardj                    binop(Iop_And32,
76960e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          binop(Iop_Shr32, mkexpr(t1), mkU8(18)),
76970e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          mkU32(1))),
769899dd03e04a6914d90d5fee727d61d76905334becflorian               mkU32(1),
769999dd03e04a6914d90d5fee727d61d76905334becflorian               mkU32(0)))
77000e9a0f551e190b475150dcd6bc4500033eb05338sewardj       );
77010e9a0f551e190b475150dcd6bc4500033eb05338sewardj
77020e9a0f551e190b475150dcd6bc4500033eb05338sewardj   if (emit_AC_emwarn) {
77030e9a0f551e190b475150dcd6bc4500033eb05338sewardj      put_emwarn( mkU32(EmWarn_X86_acFlag) );
77040e9a0f551e190b475150dcd6bc4500033eb05338sewardj      stmt(
77050e9a0f551e190b475150dcd6bc4500033eb05338sewardj         IRStmt_Exit(
77060e9a0f551e190b475150dcd6bc4500033eb05338sewardj            binop( Iop_CmpNE32,
77070e9a0f551e190b475150dcd6bc4500033eb05338sewardj                   binop(Iop_And32, mkexpr(t1), mkU32(1<<18)),
77080e9a0f551e190b475150dcd6bc4500033eb05338sewardj                   mkU32(0) ),
77090e9a0f551e190b475150dcd6bc4500033eb05338sewardj            Ijk_EmWarn,
7710c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            IRConst_U32( next_insn_EIP ),
7711c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            OFFB_EIP
77120e9a0f551e190b475150dcd6bc4500033eb05338sewardj         )
77130e9a0f551e190b475150dcd6bc4500033eb05338sewardj      );
77140e9a0f551e190b475150dcd6bc4500033eb05338sewardj   }
77150e9a0f551e190b475150dcd6bc4500033eb05338sewardj}
77160e9a0f551e190b475150dcd6bc4500033eb05338sewardj
77174cb918d355cef4e7640d374346852db4556f3524sewardj
7718150c9cddb753ad4dc38f43484144523174d38b02sewardj/* Helper for the SSSE3 (not SSE3) PMULHRSW insns.  Given two 64-bit
7719150c9cddb753ad4dc38f43484144523174d38b02sewardj   values (aa,bb), computes, for each of the 4 16-bit lanes:
7720150c9cddb753ad4dc38f43484144523174d38b02sewardj
7721150c9cddb753ad4dc38f43484144523174d38b02sewardj   (((aa_lane *s32 bb_lane) >>u 14) + 1) >>u 1
7722150c9cddb753ad4dc38f43484144523174d38b02sewardj*/
7723150c9cddb753ad4dc38f43484144523174d38b02sewardjstatic IRExpr* dis_PMULHRSW_helper ( IRExpr* aax, IRExpr* bbx )
7724150c9cddb753ad4dc38f43484144523174d38b02sewardj{
7725150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp aa      = newTemp(Ity_I64);
7726150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp bb      = newTemp(Ity_I64);
7727150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp aahi32s = newTemp(Ity_I64);
7728150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp aalo32s = newTemp(Ity_I64);
7729150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp bbhi32s = newTemp(Ity_I64);
7730150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp bblo32s = newTemp(Ity_I64);
7731150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp rHi     = newTemp(Ity_I64);
7732150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp rLo     = newTemp(Ity_I64);
7733150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp one32x2 = newTemp(Ity_I64);
7734150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign(aa, aax);
7735150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign(bb, bbx);
7736150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( aahi32s,
7737150c9cddb753ad4dc38f43484144523174d38b02sewardj           binop(Iop_SarN32x2,
7738150c9cddb753ad4dc38f43484144523174d38b02sewardj                 binop(Iop_InterleaveHI16x4, mkexpr(aa), mkexpr(aa)),
7739150c9cddb753ad4dc38f43484144523174d38b02sewardj                 mkU8(16) ));
7740150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( aalo32s,
7741150c9cddb753ad4dc38f43484144523174d38b02sewardj           binop(Iop_SarN32x2,
7742150c9cddb753ad4dc38f43484144523174d38b02sewardj                 binop(Iop_InterleaveLO16x4, mkexpr(aa), mkexpr(aa)),
7743150c9cddb753ad4dc38f43484144523174d38b02sewardj                 mkU8(16) ));
7744150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( bbhi32s,
7745150c9cddb753ad4dc38f43484144523174d38b02sewardj           binop(Iop_SarN32x2,
7746150c9cddb753ad4dc38f43484144523174d38b02sewardj                 binop(Iop_InterleaveHI16x4, mkexpr(bb), mkexpr(bb)),
7747150c9cddb753ad4dc38f43484144523174d38b02sewardj                 mkU8(16) ));
7748150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( bblo32s,
7749150c9cddb753ad4dc38f43484144523174d38b02sewardj           binop(Iop_SarN32x2,
7750150c9cddb753ad4dc38f43484144523174d38b02sewardj                 binop(Iop_InterleaveLO16x4, mkexpr(bb), mkexpr(bb)),
7751150c9cddb753ad4dc38f43484144523174d38b02sewardj                 mkU8(16) ));
7752150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign(one32x2, mkU64( (1ULL << 32) + 1 ));
7753150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign(
7754150c9cddb753ad4dc38f43484144523174d38b02sewardj      rHi,
7755150c9cddb753ad4dc38f43484144523174d38b02sewardj      binop(
7756150c9cddb753ad4dc38f43484144523174d38b02sewardj         Iop_ShrN32x2,
7757150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(
7758150c9cddb753ad4dc38f43484144523174d38b02sewardj            Iop_Add32x2,
7759150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(
7760150c9cddb753ad4dc38f43484144523174d38b02sewardj               Iop_ShrN32x2,
7761150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_Mul32x2, mkexpr(aahi32s), mkexpr(bbhi32s)),
7762150c9cddb753ad4dc38f43484144523174d38b02sewardj               mkU8(14)
7763150c9cddb753ad4dc38f43484144523174d38b02sewardj            ),
7764150c9cddb753ad4dc38f43484144523174d38b02sewardj            mkexpr(one32x2)
7765150c9cddb753ad4dc38f43484144523174d38b02sewardj         ),
7766150c9cddb753ad4dc38f43484144523174d38b02sewardj         mkU8(1)
7767150c9cddb753ad4dc38f43484144523174d38b02sewardj      )
7768150c9cddb753ad4dc38f43484144523174d38b02sewardj   );
7769150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign(
7770150c9cddb753ad4dc38f43484144523174d38b02sewardj      rLo,
7771150c9cddb753ad4dc38f43484144523174d38b02sewardj      binop(
7772150c9cddb753ad4dc38f43484144523174d38b02sewardj         Iop_ShrN32x2,
7773150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(
7774150c9cddb753ad4dc38f43484144523174d38b02sewardj            Iop_Add32x2,
7775150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(
7776150c9cddb753ad4dc38f43484144523174d38b02sewardj               Iop_ShrN32x2,
7777150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_Mul32x2, mkexpr(aalo32s), mkexpr(bblo32s)),
7778150c9cddb753ad4dc38f43484144523174d38b02sewardj               mkU8(14)
7779150c9cddb753ad4dc38f43484144523174d38b02sewardj            ),
7780150c9cddb753ad4dc38f43484144523174d38b02sewardj            mkexpr(one32x2)
7781150c9cddb753ad4dc38f43484144523174d38b02sewardj         ),
7782150c9cddb753ad4dc38f43484144523174d38b02sewardj         mkU8(1)
7783150c9cddb753ad4dc38f43484144523174d38b02sewardj      )
7784150c9cddb753ad4dc38f43484144523174d38b02sewardj   );
7785150c9cddb753ad4dc38f43484144523174d38b02sewardj   return
7786150c9cddb753ad4dc38f43484144523174d38b02sewardj      binop(Iop_CatEvenLanes16x4, mkexpr(rHi), mkexpr(rLo));
7787150c9cddb753ad4dc38f43484144523174d38b02sewardj}
7788150c9cddb753ad4dc38f43484144523174d38b02sewardj
7789150c9cddb753ad4dc38f43484144523174d38b02sewardj/* Helper for the SSSE3 (not SSE3) PSIGN{B,W,D} insns.  Given two 64-bit
7790150c9cddb753ad4dc38f43484144523174d38b02sewardj   values (aa,bb), computes, for each lane:
7791150c9cddb753ad4dc38f43484144523174d38b02sewardj
7792150c9cddb753ad4dc38f43484144523174d38b02sewardj          if aa_lane < 0 then - bb_lane
7793150c9cddb753ad4dc38f43484144523174d38b02sewardj     else if aa_lane > 0 then bb_lane
7794150c9cddb753ad4dc38f43484144523174d38b02sewardj     else 0
7795150c9cddb753ad4dc38f43484144523174d38b02sewardj*/
7796150c9cddb753ad4dc38f43484144523174d38b02sewardjstatic IRExpr* dis_PSIGN_helper ( IRExpr* aax, IRExpr* bbx, Int laneszB )
7797150c9cddb753ad4dc38f43484144523174d38b02sewardj{
7798150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp aa       = newTemp(Ity_I64);
7799150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp bb       = newTemp(Ity_I64);
7800150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp zero     = newTemp(Ity_I64);
7801150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp bbNeg    = newTemp(Ity_I64);
7802150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp negMask  = newTemp(Ity_I64);
7803150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp posMask  = newTemp(Ity_I64);
7804150c9cddb753ad4dc38f43484144523174d38b02sewardj   IROp   opSub    = Iop_INVALID;
7805150c9cddb753ad4dc38f43484144523174d38b02sewardj   IROp   opCmpGTS = Iop_INVALID;
7806150c9cddb753ad4dc38f43484144523174d38b02sewardj
7807150c9cddb753ad4dc38f43484144523174d38b02sewardj   switch (laneszB) {
7808150c9cddb753ad4dc38f43484144523174d38b02sewardj      case 1: opSub = Iop_Sub8x8;  opCmpGTS = Iop_CmpGT8Sx8;  break;
7809150c9cddb753ad4dc38f43484144523174d38b02sewardj      case 2: opSub = Iop_Sub16x4; opCmpGTS = Iop_CmpGT16Sx4; break;
7810150c9cddb753ad4dc38f43484144523174d38b02sewardj      case 4: opSub = Iop_Sub32x2; opCmpGTS = Iop_CmpGT32Sx2; break;
7811150c9cddb753ad4dc38f43484144523174d38b02sewardj      default: vassert(0);
7812150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
7813150c9cddb753ad4dc38f43484144523174d38b02sewardj
7814150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( aa,      aax );
7815150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( bb,      bbx );
7816150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( zero,    mkU64(0) );
7817150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( bbNeg,   binop(opSub,    mkexpr(zero), mkexpr(bb)) );
7818150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( negMask, binop(opCmpGTS, mkexpr(zero), mkexpr(aa)) );
7819150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( posMask, binop(opCmpGTS, mkexpr(aa),   mkexpr(zero)) );
7820150c9cddb753ad4dc38f43484144523174d38b02sewardj
7821150c9cddb753ad4dc38f43484144523174d38b02sewardj   return
7822150c9cddb753ad4dc38f43484144523174d38b02sewardj      binop(Iop_Or64,
7823150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64, mkexpr(bb),    mkexpr(posMask)),
7824150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64, mkexpr(bbNeg), mkexpr(negMask)) );
7825150c9cddb753ad4dc38f43484144523174d38b02sewardj
7826150c9cddb753ad4dc38f43484144523174d38b02sewardj}
7827150c9cddb753ad4dc38f43484144523174d38b02sewardj
7828150c9cddb753ad4dc38f43484144523174d38b02sewardj/* Helper for the SSSE3 (not SSE3) PABS{B,W,D} insns.  Given a 64-bit
7829150c9cddb753ad4dc38f43484144523174d38b02sewardj   value aa, computes, for each lane
7830150c9cddb753ad4dc38f43484144523174d38b02sewardj
7831150c9cddb753ad4dc38f43484144523174d38b02sewardj   if aa < 0 then -aa else aa
7832150c9cddb753ad4dc38f43484144523174d38b02sewardj
7833150c9cddb753ad4dc38f43484144523174d38b02sewardj   Note that the result is interpreted as unsigned, so that the
7834150c9cddb753ad4dc38f43484144523174d38b02sewardj   absolute value of the most negative signed input can be
7835150c9cddb753ad4dc38f43484144523174d38b02sewardj   represented.
7836150c9cddb753ad4dc38f43484144523174d38b02sewardj*/
7837150c9cddb753ad4dc38f43484144523174d38b02sewardjstatic IRExpr* dis_PABS_helper ( IRExpr* aax, Int laneszB )
7838150c9cddb753ad4dc38f43484144523174d38b02sewardj{
7839150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp aa      = newTemp(Ity_I64);
7840150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp zero    = newTemp(Ity_I64);
7841150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp aaNeg   = newTemp(Ity_I64);
7842150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp negMask = newTemp(Ity_I64);
7843150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp posMask = newTemp(Ity_I64);
7844150c9cddb753ad4dc38f43484144523174d38b02sewardj   IROp   opSub   = Iop_INVALID;
7845150c9cddb753ad4dc38f43484144523174d38b02sewardj   IROp   opSarN  = Iop_INVALID;
7846150c9cddb753ad4dc38f43484144523174d38b02sewardj
7847150c9cddb753ad4dc38f43484144523174d38b02sewardj   switch (laneszB) {
7848150c9cddb753ad4dc38f43484144523174d38b02sewardj      case 1: opSub = Iop_Sub8x8;  opSarN = Iop_SarN8x8;  break;
7849150c9cddb753ad4dc38f43484144523174d38b02sewardj      case 2: opSub = Iop_Sub16x4; opSarN = Iop_SarN16x4; break;
7850150c9cddb753ad4dc38f43484144523174d38b02sewardj      case 4: opSub = Iop_Sub32x2; opSarN = Iop_SarN32x2; break;
7851150c9cddb753ad4dc38f43484144523174d38b02sewardj      default: vassert(0);
7852150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
7853150c9cddb753ad4dc38f43484144523174d38b02sewardj
7854150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( aa,      aax );
7855150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( negMask, binop(opSarN, mkexpr(aa), mkU8(8*laneszB-1)) );
7856150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( posMask, unop(Iop_Not64, mkexpr(negMask)) );
7857150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( zero,    mkU64(0) );
7858150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( aaNeg,   binop(opSub, mkexpr(zero), mkexpr(aa)) );
7859150c9cddb753ad4dc38f43484144523174d38b02sewardj   return
7860150c9cddb753ad4dc38f43484144523174d38b02sewardj      binop(Iop_Or64,
7861150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64, mkexpr(aa),    mkexpr(posMask)),
7862150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64, mkexpr(aaNeg), mkexpr(negMask)) );
7863150c9cddb753ad4dc38f43484144523174d38b02sewardj}
7864150c9cddb753ad4dc38f43484144523174d38b02sewardj
7865150c9cddb753ad4dc38f43484144523174d38b02sewardjstatic IRExpr* dis_PALIGNR_XMM_helper ( IRTemp hi64,
7866150c9cddb753ad4dc38f43484144523174d38b02sewardj                                        IRTemp lo64, Int byteShift )
7867150c9cddb753ad4dc38f43484144523174d38b02sewardj{
7868150c9cddb753ad4dc38f43484144523174d38b02sewardj   vassert(byteShift >= 1 && byteShift <= 7);
7869150c9cddb753ad4dc38f43484144523174d38b02sewardj   return
7870150c9cddb753ad4dc38f43484144523174d38b02sewardj      binop(Iop_Or64,
7871150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_Shl64, mkexpr(hi64), mkU8(8*(8-byteShift))),
7872150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_Shr64, mkexpr(lo64), mkU8(8*byteShift))
7873150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
7874150c9cddb753ad4dc38f43484144523174d38b02sewardj}
7875150c9cddb753ad4dc38f43484144523174d38b02sewardj
7876150c9cddb753ad4dc38f43484144523174d38b02sewardj/* Generate a SIGSEGV followed by a restart of the current instruction
7877150c9cddb753ad4dc38f43484144523174d38b02sewardj   if effective_addr is not 16-aligned.  This is required behaviour
7878150c9cddb753ad4dc38f43484144523174d38b02sewardj   for some SSE3 instructions and all 128-bit SSSE3 instructions.
7879150c9cddb753ad4dc38f43484144523174d38b02sewardj   This assumes that guest_RIP_curr_instr is set correctly! */
7880150c9cddb753ad4dc38f43484144523174d38b02sewardjstatic void gen_SEGV_if_not_16_aligned ( IRTemp effective_addr )
7881150c9cddb753ad4dc38f43484144523174d38b02sewardj{
7882150c9cddb753ad4dc38f43484144523174d38b02sewardj   stmt(
7883150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRStmt_Exit(
7884150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_CmpNE32,
7885150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_And32,mkexpr(effective_addr),mkU32(0xF)),
7886150c9cddb753ad4dc38f43484144523174d38b02sewardj               mkU32(0)),
7887150c9cddb753ad4dc38f43484144523174d38b02sewardj         Ijk_SigSEGV,
7888c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         IRConst_U32(guest_EIP_curr_instr),
7889c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         OFFB_EIP
7890150c9cddb753ad4dc38f43484144523174d38b02sewardj      )
7891150c9cddb753ad4dc38f43484144523174d38b02sewardj   );
7892150c9cddb753ad4dc38f43484144523174d38b02sewardj}
7893150c9cddb753ad4dc38f43484144523174d38b02sewardj
7894150c9cddb753ad4dc38f43484144523174d38b02sewardj
7895c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj/* Helper for deciding whether a given insn (starting at the opcode
7896c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   byte) may validly be used with a LOCK prefix.  The following insns
7897c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   may be used with LOCK when their destination operand is in memory.
7898e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   AFAICS this is exactly the same for both 32-bit and 64-bit mode.
7899c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7900e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   ADD        80 /0,  81 /0,  82 /0,  83 /0,  00,  01
7901e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   OR         80 /1,  81 /1,  82 /x,  83 /1,  08,  09
7902e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   ADC        80 /2,  81 /2,  82 /2,  83 /2,  10,  11
7903e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   SBB        81 /3,  81 /3,  82 /x,  83 /3,  18,  19
7904e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   AND        80 /4,  81 /4,  82 /x,  83 /4,  20,  21
7905e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   SUB        80 /5,  81 /5,  82 /x,  83 /5,  28,  29
7906e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   XOR        80 /6,  81 /6,  82 /x,  83 /6,  30,  31
7907c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7908c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   DEC        FE /1,  FF /1
7909c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   INC        FE /0,  FF /0
7910c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7911c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   NEG        F6 /3,  F7 /3
7912c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   NOT        F6 /2,  F7 /2
7913c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7914e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   XCHG       86, 87
7915c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7916c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   BTC        0F BB,  0F BA /7
7917c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   BTR        0F B3,  0F BA /6
7918c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   BTS        0F AB,  0F BA /5
7919c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7920c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   CMPXCHG    0F B0,  0F B1
7921c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   CMPXCHG8B  0F C7 /1
7922c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7923c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   XADD       0F C0,  0F C1
7924e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7925e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   ------------------------------
7926e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7927e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   80 /0  =  addb $imm8,  rm8
7928e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   81 /0  =  addl $imm32, rm32  and  addw $imm16, rm16
7929e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   82 /0  =  addb $imm8,  rm8
7930e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   83 /0  =  addl $simm8, rm32  and  addw $simm8, rm16
7931e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7932e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   00     =  addb r8,  rm8
7933e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   01     =  addl r32, rm32  and  addw r16, rm16
7934e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7935e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   Same for ADD OR ADC SBB AND SUB XOR
7936e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7937e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   FE /1  = dec rm8
7938e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   FF /1  = dec rm32  and  dec rm16
7939e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7940e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   FE /0  = inc rm8
7941e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   FF /0  = inc rm32  and  inc rm16
7942e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7943e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   F6 /3  = neg rm8
7944e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   F7 /3  = neg rm32  and  neg rm16
7945e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7946e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   F6 /2  = not rm8
7947e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   F7 /2  = not rm32  and  not rm16
7948e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7949e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   0F BB     = btcw r16, rm16    and  btcl r32, rm32
7950e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   OF BA /7  = btcw $imm8, rm16  and  btcw $imm8, rm32
7951e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7952e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   Same for BTS, BTR
7953c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj*/
79548462d113e3efeacceb304222dada8d85f748295aflorianstatic Bool can_be_used_with_LOCK_prefix ( const UChar* opc )
7955c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj{
7956c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   switch (opc[0]) {
7957e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      case 0x00: case 0x01: case 0x08: case 0x09:
7958e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      case 0x10: case 0x11: case 0x18: case 0x19:
7959e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      case 0x20: case 0x21: case 0x28: case 0x29:
7960e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      case 0x30: case 0x31:
7961e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (!epartIsReg(opc[1]))
7962e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            return True;
7963e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         break;
7964e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7965e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      case 0x80: case 0x81: case 0x82: case 0x83:
7966e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 6
7967e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj             && !epartIsReg(opc[1]))
7968c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            return True;
7969c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         break;
7970c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7971c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      case 0xFE: case 0xFF:
7972e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 1
7973e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj             && !epartIsReg(opc[1]))
7974c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            return True;
7975c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         break;
7976c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7977c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      case 0xF6: case 0xF7:
7978e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (gregOfRM(opc[1]) >= 2 && gregOfRM(opc[1]) <= 3
7979e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj             && !epartIsReg(opc[1]))
7980c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            return True;
7981c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         break;
7982c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7983c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      case 0x86: case 0x87:
7984e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (!epartIsReg(opc[1]))
7985e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            return True;
7986e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         break;
7987c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7988c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      case 0x0F: {
7989c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         switch (opc[1]) {
7990c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            case 0xBB: case 0xB3: case 0xAB:
7991e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (!epartIsReg(opc[2]))
7992e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  return True;
7993e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               break;
7994c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            case 0xBA:
7995e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (gregOfRM(opc[2]) >= 5 && gregOfRM(opc[2]) <= 7
7996e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                   && !epartIsReg(opc[2]))
7997c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj                  return True;
7998c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               break;
7999c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            case 0xB0: case 0xB1:
8000e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (!epartIsReg(opc[2]))
8001e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  return True;
8002e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               break;
8003c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            case 0xC7:
8004e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (gregOfRM(opc[2]) == 1 && !epartIsReg(opc[2]) )
8005c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj                  return True;
8006c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               break;
8007c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            case 0xC0: case 0xC1:
8008e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (!epartIsReg(opc[2]))
8009e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  return True;
8010e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               break;
8011c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            default:
8012c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               break;
8013c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         } /* switch (opc[1]) */
8014c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         break;
8015c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      }
8016c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8017c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      default:
8018c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         break;
8019c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   } /* switch (opc[0]) */
8020c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8021c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   return False;
8022c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj}
8023c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8024021f6b420c3ce127091cdf3e1facbfabbe92100fsewardjstatic IRTemp math_BSWAP ( IRTemp t1, IRType ty )
8025021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj{
8026021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   IRTemp t2 = newTemp(ty);
8027021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   if (ty == Ity_I32) {
8028021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      assign( t2,
8029021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         binop(
8030021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj            Iop_Or32,
8031021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj            binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
8032021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj            binop(
8033021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj               Iop_Or32,
8034021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj               binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
8035021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                                mkU32(0x00FF0000)),
8036021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj               binop(Iop_Or32,
8037021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                     binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
8038021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                                      mkU32(0x0000FF00)),
8039021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                     binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
8040021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                                      mkU32(0x000000FF) )
8041021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj            )))
8042021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      );
8043021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      return t2;
8044021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   }
8045021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   if (ty == Ity_I16) {
8046021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      assign(t2,
8047021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj             binop(Iop_Or16,
8048021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                   binop(Iop_Shl16, mkexpr(t1), mkU8(8)),
8049021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                   binop(Iop_Shr16, mkexpr(t1), mkU8(8)) ));
8050021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      return t2;
8051021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   }
8052021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   vassert(0);
8053021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   /*NOTREACHED*/
8054021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   return IRTemp_INVALID;
8055021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj}
8056c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8057c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*------------------------------------------------------------*/
8058ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj/*--- Disassemble a single instruction                     ---*/
8059c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*------------------------------------------------------------*/
8060c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8061e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj/* Disassemble a single instruction into IR.  The instruction is
8062e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   located in host memory at &guest_code[delta].  *expect_CAS is set
8063e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   to True if the resulting IR is expected to contain an IRCAS
8064e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   statement, and False if it's not expected to.  This makes it
8065e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   possible for the caller of disInstr_X86_WRK to check that
8066e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   LOCK-prefixed instructions are at least plausibly translated, in
8067e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   that it becomes possible to check that a (validly) LOCK-prefixed
8068e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   instruction generates a translation containing an IRCAS, and
8069e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   instructions without LOCK prefixes don't generate translations
8070e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   containing an IRCAS.
8071e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj*/
80729e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardjstatic
8073e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardjDisResult disInstr_X86_WRK (
8074e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj             /*OUT*/Bool* expect_CAS,
8075beac530a718fcc646bc61fe60a86f599df54e1d7florian             Bool         (*resteerOkFn) ( /*opaque*/void*, Addr ),
8076984d9b164dd17f07e603c41fe1e506e641e57d18sewardj             Bool         resteerCisOk,
8077c716aea1cafe66ee431dc7d6909c98f18788a028sewardj             void*        callback_opaque,
80789e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj             Long         delta64,
8079cacba8e675988fbf21b08feea1f317a9c896c053florian             const VexArchInfo* archinfo,
8080cacba8e675988fbf21b08feea1f317a9c896c053florian             const VexAbiInfo*  vbi,
8081442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj             Bool         sigill_diag
80829e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj          )
8083c9a6570e86f4252f8a486b4df48de8710d357a4asewardj{
8084ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj   IRType    ty;
8085b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   IRTemp    addr, t0, t1, t2, t3, t4, t5, t6;
8086ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj   Int       alen;
8087c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   UChar     opc, modrm, abyte, pre;
8088ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj   UInt      d32;
8089c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar     dis_buf[50];
8090c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   Int       am_sz, d_sz, n_prefixes;
80919e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   DisResult dres;
80928462d113e3efeacceb304222dada8d85f748295aflorian   const UChar* insn; /* used in SSE decoders */
8093ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj
80949e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   /* The running delta */
80959e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   Int delta = (Int)delta64;
80969e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
8097c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* Holds eip at the start of the insn, so that we can print
8098c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      consistent error messages for unimplemented insns. */
80999e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   Int delta_start = delta;
8100c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8101c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* sz denotes the nominal data-op size of the insn; we change it to
8102c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      2 if an 0x66 prefix is seen */
8103c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   Int sz = 4;
8104c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8105c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* sorb holds the segment-override-prefix byte, if any.  Zero if no
8106ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      prefix has been seen, else one of {0x26, 0x36, 0x3E, 0x64, 0x65}
8107c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      indicating the prefix.  */
8108c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   UChar sorb = 0;
8109c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8110c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   /* Gets set to True if a LOCK prefix is seen. */
8111c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   Bool pfx_lock = False;
8112c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
81139e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   /* Set result defaults. */
8114c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres.whatNext    = Dis_Continue;
8115c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres.len         = 0;
8116c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres.continueAt  = 0;
8117ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   dres.hint        = Dis_HintNone;
8118c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres.jk_StopHere = Ijk_INVALID;
8119ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj
8120e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   *expect_CAS = False;
8121e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
8122b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
8123c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8124e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   vassert(guest_EIP_bbstart + delta == guest_EIP_curr_instr);
81259e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   DIP("\t0x%x:  ", guest_EIP_bbstart+delta);
81269e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
8127ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   /* Spot "Special" instructions (see comment at top of file). */
8128750f407b6be1aac303964a219acf0a6de8b8c4dasewardj   {
81298462d113e3efeacceb304222dada8d85f748295aflorian      const UChar* code = guest_code + delta;
8130ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj      /* Spot the 12-byte preamble:
8131ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         C1C703   roll $3,  %edi
8132ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         C1C70D   roll $13, %edi
8133ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         C1C71D   roll $29, %edi
8134ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         C1C713   roll $19, %edi
8135750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      */
8136ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj      if (code[ 0] == 0xC1 && code[ 1] == 0xC7 && code[ 2] == 0x03 &&
8137ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj          code[ 3] == 0xC1 && code[ 4] == 0xC7 && code[ 5] == 0x0D &&
8138ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj          code[ 6] == 0xC1 && code[ 7] == 0xC7 && code[ 8] == 0x1D &&
8139ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj          code[ 9] == 0xC1 && code[10] == 0xC7 && code[11] == 0x13) {
8140ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         /* Got a "Special" instruction preamble.  Which one is it? */
8141ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         if (code[12] == 0x87 && code[13] == 0xDB /* xchgl %ebx,%ebx */) {
8142ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            /* %EDX = client_request ( %EAX ) */
8143ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            DIP("%%edx = client_request ( %%eax )\n");
8144ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            delta += 14;
8145c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_lit(&dres, Ijk_ClientReq, guest_EIP_bbstart+delta);
8146c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres.whatNext == Dis_StopHere);
8147ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            goto decode_success;
8148ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         }
8149ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         else
8150ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         if (code[12] == 0x87 && code[13] == 0xC9 /* xchgl %ecx,%ecx */) {
8151ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            /* %EAX = guest_NRADDR */
8152ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            DIP("%%eax = guest_NRADDR\n");
8153ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            delta += 14;
8154ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            putIReg(4, R_EAX, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
8155ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            goto decode_success;
8156ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         }
8157ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         else
8158ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         if (code[12] == 0x87 && code[13] == 0xD2 /* xchgl %edx,%edx */) {
8159ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            /* call-noredir *%EAX */
8160ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            DIP("call-noredir *%%eax\n");
8161ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            delta += 14;
8162ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            t1 = newTemp(Ity_I32);
8163ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            assign(t1, getIReg(4,R_EAX));
8164ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            t2 = newTemp(Ity_I32);
8165ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
8166ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            putIReg(4, R_ESP, mkexpr(t2));
8167ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta));
8168c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_treg(&dres, Ijk_NoRedir, t1);
8169c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres.whatNext == Dis_StopHere);
8170ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            goto decode_success;
8171ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         }
81722245ce9e834193d49261b8a433b4a0bd128c878eflorian         else
81732245ce9e834193d49261b8a433b4a0bd128c878eflorian         if (code[12] == 0x87 && code[13] == 0xFF /* xchgl %edi,%edi */) {
81742245ce9e834193d49261b8a433b4a0bd128c878eflorian            /* IR injection */
81752245ce9e834193d49261b8a433b4a0bd128c878eflorian            DIP("IR injection\n");
81762245ce9e834193d49261b8a433b4a0bd128c878eflorian            vex_inject_ir(irsb, Iend_LE);
81772245ce9e834193d49261b8a433b4a0bd128c878eflorian
81782245ce9e834193d49261b8a433b4a0bd128c878eflorian            // Invalidate the current insn. The reason is that the IRop we're
81792245ce9e834193d49261b8a433b4a0bd128c878eflorian            // injecting here can change. In which case the translation has to
81802245ce9e834193d49261b8a433b4a0bd128c878eflorian            // be redone. For ease of handling, we simply invalidate all the
81812245ce9e834193d49261b8a433b4a0bd128c878eflorian            // time.
818205f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj            stmt(IRStmt_Put(OFFB_CMSTART, mkU32(guest_EIP_curr_instr)));
818305f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj            stmt(IRStmt_Put(OFFB_CMLEN,   mkU32(14)));
81842245ce9e834193d49261b8a433b4a0bd128c878eflorian
81852245ce9e834193d49261b8a433b4a0bd128c878eflorian            delta += 14;
81862245ce9e834193d49261b8a433b4a0bd128c878eflorian
81872245ce9e834193d49261b8a433b4a0bd128c878eflorian            stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_bbstart + delta) ) );
81882245ce9e834193d49261b8a433b4a0bd128c878eflorian            dres.whatNext    = Dis_StopHere;
818905f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj            dres.jk_StopHere = Ijk_InvalICache;
81902245ce9e834193d49261b8a433b4a0bd128c878eflorian            goto decode_success;
81912245ce9e834193d49261b8a433b4a0bd128c878eflorian         }
8192ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         /* We don't know what it is. */
8193ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         goto decode_failure;
8194ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         /*NOTREACHED*/
8195750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      }
8196750f407b6be1aac303964a219acf0a6de8b8c4dasewardj   }
8197c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8198c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   /* Handle a couple of weird-ass NOPs that have been observed in the
8199c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      wild. */
8200c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   {
82018462d113e3efeacceb304222dada8d85f748295aflorian      const UChar* code = guest_code + delta;
8202c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      /* Sun's JVM 1.5.0 uses the following as a NOP:
8203c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         26 2E 64 65 90  %es:%cs:%fs:%gs:nop */
8204c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      if (code[0] == 0x26 && code[1] == 0x2E && code[2] == 0x64
8205c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj          && code[3] == 0x65 && code[4] == 0x90) {
8206c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         DIP("%%es:%%cs:%%fs:%%gs:nop\n");
8207c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         delta += 5;
8208c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         goto decode_success;
8209bb3f52db829c572ec04002392e8a5056b63affb3sewardj      }
8210deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj      /* Don't barf on recent binutils padding,
8211deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         all variants of which are: nopw %cs:0x0(%eax,%eax,1)
8212deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         66 2e 0f 1f 84 00 00 00 00 00
8213deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         66 66 2e 0f 1f 84 00 00 00 00 00
8214deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         66 66 66 2e 0f 1f 84 00 00 00 00 00
8215deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8216deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8217deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         66 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8218deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj      */
8219deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj      if (code[0] == 0x66) {
8220deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         Int data16_cnt;
8221deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         for (data16_cnt = 1; data16_cnt < 6; data16_cnt++)
8222deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj            if (code[data16_cnt] != 0x66)
8223deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj               break;
8224deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         if (code[data16_cnt] == 0x2E && code[data16_cnt + 1] == 0x0F
8225deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj             && code[data16_cnt + 2] == 0x1F && code[data16_cnt + 3] == 0x84
8226deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj             && code[data16_cnt + 4] == 0x00 && code[data16_cnt + 5] == 0x00
8227deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj             && code[data16_cnt + 6] == 0x00 && code[data16_cnt + 7] == 0x00
8228deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj             && code[data16_cnt + 8] == 0x00 ) {
8229deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj            DIP("nopw %%cs:0x0(%%eax,%%eax,1)\n");
8230deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj            delta += 9 + data16_cnt;
8231deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj            goto decode_success;
8232deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         }
8233ce4a282154b918641db59c83541d9d573a761decsewardj      }
8234bb3f52db829c572ec04002392e8a5056b63affb3sewardj
8235ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      // Intel CET requires the following opcodes to be treated as NOPs
8236ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      // with any prefix and ModRM, SIB and disp combination:
8237ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      // "0F 19", "0F 1C", "0F 1D", "0F 1E", "0F 1F"
8238ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      UInt opcode_index = 0;
8239ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      // Skip any prefix combination
8240ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      UInt addr_override = 0;
8241ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      UInt temp_sz = 4;
8242ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      Bool is_prefix = True;
8243ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      while (is_prefix) {
8244ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes         switch (code[opcode_index]) {
8245ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes            case 0x66:
8246ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               temp_sz = 2;
8247ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               opcode_index++;
8248ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               break;
8249ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes            case 0x67:
8250ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               addr_override = 1;
8251ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               opcode_index++;
8252ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               break;
8253ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes            case 0x26: case 0x3E: // if we set segment override here,
8254ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes            case 0x64: case 0x65: //  disAMode segfaults
8255ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes            case 0x2E: case 0x36:
8256ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes            case 0xF0: case 0xF2: case 0xF3:
8257ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               opcode_index++;
8258ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               break;
8259ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes            default:
8260ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               is_prefix = False;
8261ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes         }
8262ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      }
8263ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      // Check the opcode
8264ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      if (code[opcode_index] == 0x0F) {
8265ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes         switch (code[opcode_index+1]) {
8266ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes            case 0x19:
8267ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes            case 0x1C: case 0x1D:
8268ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes            case 0x1E: case 0x1F:
8269ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               delta += opcode_index+2;
8270ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               modrm = getUChar(delta);
8271ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               if (epartIsReg(modrm)) {
8272ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                  delta += 1;
8273ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                  DIP("nop%c\n", nameISize(temp_sz));
8274ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               }
8275ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               else {
8276ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                  addr = disAMode(&alen, 0/*"no sorb"*/, delta, dis_buf);
8277ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                  delta += alen - addr_override;
8278ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                  DIP("nop%c %s\n", nameISize(temp_sz), dis_buf);
8279ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               }
8280ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               goto decode_success;
8281ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes            default:
8282ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes               break;
8283ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes         }
8284ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      }
8285ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   }
8286c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   /* Normal instruction handling starts here. */
8287c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8288c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   /* Deal with some but not all prefixes:
8289c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         66(oso)
8290c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         F0(lock)
8291c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         2E(cs:) 3E(ds:) 26(es:) 64(fs:) 65(gs:) 36(ss:)
8292c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      Not dealt with (left in place):
8293c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         F2 F3
8294c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   */
8295c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   n_prefixes = 0;
8296c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   while (True) {
8297c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      if (n_prefixes > 7) goto decode_failure;
8298c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      pre = getUChar(delta);
8299c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      switch (pre) {
8300c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0x66:
8301c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            sz = 2;
8302c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            break;
8303c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0xF0:
8304c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            pfx_lock = True;
8305e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            *expect_CAS = True;
8306c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            break;
8307c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0x3E: /* %DS: */
8308c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0x26: /* %ES: */
8309c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0x64: /* %FS: */
8310c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0x65: /* %GS: */
8311ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes         case 0x36: /* %SS: */
8312c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            if (sorb != 0)
8313c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               goto decode_failure; /* only one seg override allowed */
8314c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            sorb = pre;
8315c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            break;
8316c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0x2E: { /* %CS: */
8317c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            /* 2E prefix on a conditional branch instruction is a
8318c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               branch-prediction hint, which can safely be ignored.  */
8319c9a6570e86f4252f8a486b4df48de8710d357a4asewardj            UChar op1 = getIByte(delta+1);
8320c9a6570e86f4252f8a486b4df48de8710d357a4asewardj            UChar op2 = getIByte(delta+2);
8321c9a6570e86f4252f8a486b4df48de8710d357a4asewardj            if ((op1 >= 0x70 && op1 <= 0x7F)
8322c9a6570e86f4252f8a486b4df48de8710d357a4asewardj                || (op1 == 0xE3)
8323c9a6570e86f4252f8a486b4df48de8710d357a4asewardj                || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
83244dfb199ead988f45252befaec1ae849e9c927509sewardj               if (0) vex_printf("vex x86->IR: ignoring branch hint\n");
8325c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            } else {
8326c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               /* All other CS override cases are not handled */
8327c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               goto decode_failure;
832887f471d72daee180f8f1e19433ba1c164decdee4sewardj            }
8329c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            break;
833087f471d72daee180f8f1e19433ba1c164decdee4sewardj         }
8331c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         default:
8332c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            goto not_a_prefix;
8333c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      }
8334c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      n_prefixes++;
8335c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      delta++;
8336c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   }
8337c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8338c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   not_a_prefix:
8339c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8340c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   /* Now we should be looking at the primary opcode byte or the
8341c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      leading F2 or F3.  Check that any LOCK prefix is actually
8342c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      allowed. */
8343c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8344c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   if (pfx_lock) {
83458462d113e3efeacceb304222dada8d85f748295aflorian     if (can_be_used_with_LOCK_prefix( &guest_code[delta] )) {
8346c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         DIP("lock ");
8347c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      } else {
8348e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         *expect_CAS = False;
83499c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj         goto decode_failure;
8350c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      }
8351c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   }
8352c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8353c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8354c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   /* ---------------------------------------------------- */
8355c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   /* --- The SSE decoder.                             --- */
8356c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   /* ---------------------------------------------------- */
8357c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
83584cb918d355cef4e7640d374346852db4556f3524sewardj   /* What did I do to deserve SSE ?  Perhaps I was really bad in a
83594cb918d355cef4e7640d374346852db4556f3524sewardj      previous life? */
83604cb918d355cef4e7640d374346852db4556f3524sewardj
83619df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj   /* Note, this doesn't handle SSE2 or SSE3.  That is handled in a
83629df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj      later section, further on. */
83639df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj
83648462d113e3efeacceb304222dada8d85f748295aflorian   insn = &guest_code[delta];
8365a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8366a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   /* Treat fxsave specially.  It should be doable even on an SSE0
8367a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      (Pentium-II class) CPU.  Hence be prepared to handle it on
8368a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      any subarchitecture variant.
8369a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   */
8370a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8371a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
8372a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8373a0e83b06f304527e3e9aec527c344e35e7023d76sewardj       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
83749a036bf85bea7071ee235b8f7010e574ae71c6f0sewardj      IRDirty* d;
8375a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      modrm = getIByte(delta+2);
8376a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      vassert(sz == 4);
8377a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      vassert(!epartIsReg(modrm));
8378a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8379a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8380a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      delta += 2+alen;
8381ec993dea5afed8192e4419856025a18a3b7cb2cbsewardj      gen_SEGV_if_not_16_aligned(addr);
8382a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
838333dd31b1bcc175495b96222fa278062fd6116899sewardj      DIP("fxsave %s\n", dis_buf);
8384a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8385a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      /* Uses dirty helper:
8386a0e83b06f304527e3e9aec527c344e35e7023d76sewardj            void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
83879a036bf85bea7071ee235b8f7010e574ae71c6f0sewardj      d = unsafeIRDirty_0_N (
83889a036bf85bea7071ee235b8f7010e574ae71c6f0sewardj             0/*regparms*/,
83899a036bf85bea7071ee235b8f7010e574ae71c6f0sewardj             "x86g_dirtyhelper_FXSAVE",
83909a036bf85bea7071ee235b8f7010e574ae71c6f0sewardj             &x86g_dirtyhelper_FXSAVE,
8391ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes             mkIRExprVec_2( IRExpr_GSPTR(), mkexpr(addr) )
83929a036bf85bea7071ee235b8f7010e574ae71c6f0sewardj          );
8393a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8394a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      /* declare we're writing memory */
8395a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->mFx   = Ifx_Write;
8396a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->mAddr = mkexpr(addr);
8397c9069f2908814843e9a4da00da9c8905440195a6sewardj      d->mSize = 464; /* according to recent Intel docs */
8398a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8399a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      /* declare we're reading guest state */
8400a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->nFxState = 7;
8401c9069f2908814843e9a4da00da9c8905440195a6sewardj      vex_bzero(&d->fxState, sizeof(d->fxState));
8402a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8403a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[0].fx     = Ifx_Read;
8404a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[0].offset = OFFB_FTOP;
8405a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[0].size   = sizeof(UInt);
8406a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8407a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[1].fx     = Ifx_Read;
8408a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[1].offset = OFFB_FPREGS;
8409a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[1].size   = 8 * sizeof(ULong);
8410a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8411a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[2].fx     = Ifx_Read;
8412a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[2].offset = OFFB_FPTAGS;
8413a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[2].size   = 8 * sizeof(UChar);
8414a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8415a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[3].fx     = Ifx_Read;
8416a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[3].offset = OFFB_FPROUND;
8417a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[3].size   = sizeof(UInt);
8418a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8419a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[4].fx     = Ifx_Read;
8420a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[4].offset = OFFB_FC3210;
8421a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[4].size   = sizeof(UInt);
8422a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8423a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[5].fx     = Ifx_Read;
8424a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[5].offset = OFFB_XMM0;
8425a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[5].size   = 8 * sizeof(U128);
8426a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8427a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[6].fx     = Ifx_Read;
8428a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[6].offset = OFFB_SSEROUND;
8429a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[6].size   = sizeof(UInt);
8430a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8431a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8432a0e83b06f304527e3e9aec527c344e35e7023d76sewardj	 images are packed back-to-back.  If not, the value of
8433a0e83b06f304527e3e9aec527c344e35e7023d76sewardj	 d->fxState[5].size is wrong. */
8434a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      vassert(16 == sizeof(U128));
8435a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
84363800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84373800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      stmt( IRStmt_Dirty(d) );
84383800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84393800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      goto decode_success;
84403800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj   }
84413800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84423800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj   /* 0F AE /1 = FXRSTOR m512 -- read x87 and SSE state from memory */
84433800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
84443800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 1) {
84453800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      IRDirty* d;
84463800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      modrm = getIByte(delta+2);
84473800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      vassert(sz == 4);
84483800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      vassert(!epartIsReg(modrm));
84493800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84503800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
84513800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      delta += 2+alen;
8452ec993dea5afed8192e4419856025a18a3b7cb2cbsewardj      gen_SEGV_if_not_16_aligned(addr);
84533800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84543800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      DIP("fxrstor %s\n", dis_buf);
84553800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84563800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      /* Uses dirty helper:
84576ef84bed9bb3af22060eb1759788034602bbcc88florian            VexEmNote x86g_do_FXRSTOR ( VexGuestX86State*, UInt )
8458ec993dea5afed8192e4419856025a18a3b7cb2cbsewardj         NOTE:
84596ef84bed9bb3af22060eb1759788034602bbcc88florian            the VexEmNote value is simply ignored (unlike for FRSTOR)
8460ec993dea5afed8192e4419856025a18a3b7cb2cbsewardj      */
84613800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d = unsafeIRDirty_0_N (
84623800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj             0/*regparms*/,
84633800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj             "x86g_dirtyhelper_FXRSTOR",
84643800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj             &x86g_dirtyhelper_FXRSTOR,
8465ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes             mkIRExprVec_2( IRExpr_GSPTR(), mkexpr(addr) )
84663800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj          );
84673800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84683800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      /* declare we're reading memory */
84693800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->mFx   = Ifx_Read;
84703800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->mAddr = mkexpr(addr);
8471c9069f2908814843e9a4da00da9c8905440195a6sewardj      d->mSize = 464; /* according to recent Intel docs */
84723800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84733800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      /* declare we're writing guest state */
84743800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->nFxState = 7;
8475c9069f2908814843e9a4da00da9c8905440195a6sewardj      vex_bzero(&d->fxState, sizeof(d->fxState));
84763800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84773800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[0].fx     = Ifx_Write;
84783800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[0].offset = OFFB_FTOP;
84793800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[0].size   = sizeof(UInt);
84803800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84813800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[1].fx     = Ifx_Write;
84823800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[1].offset = OFFB_FPREGS;
84833800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[1].size   = 8 * sizeof(ULong);
84843800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84853800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[2].fx     = Ifx_Write;
84863800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[2].offset = OFFB_FPTAGS;
84873800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[2].size   = 8 * sizeof(UChar);
84883800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84893800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[3].fx     = Ifx_Write;
84903800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[3].offset = OFFB_FPROUND;
84913800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[3].size   = sizeof(UInt);
84923800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84933800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[4].fx     = Ifx_Write;
84943800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[4].offset = OFFB_FC3210;
84953800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[4].size   = sizeof(UInt);
84963800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84973800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[5].fx     = Ifx_Write;
84983800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[5].offset = OFFB_XMM0;
84993800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[5].size   = 8 * sizeof(U128);
85003800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
85013800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[6].fx     = Ifx_Write;
85023800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[6].offset = OFFB_SSEROUND;
85033800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[6].size   = sizeof(UInt);
85043800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
85053800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      /* Be paranoid ... this assertion tries to ensure the 8 %xmm
85063800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj	 images are packed back-to-back.  If not, the value of
85073800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj	 d->fxState[5].size is wrong. */
85083800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      vassert(16 == sizeof(U128));
85093800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8510a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8511a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      stmt( IRStmt_Dirty(d) );
8512a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8513a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      goto decode_success;
8514a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   }
8515a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8516a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   /* ------ SSE decoder main ------ */
8517a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
85189df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj   /* Skip parts of the decoder which don't apply given the stated
85199df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj      guest subarchitecture. */
85205117ce116f47141cb23d1b49cc826e19323add97sewardj   if (archinfo->hwcaps == 0/*baseline, no sse at all*/)
85219df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj      goto after_sse_decoders;
85226c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
85236c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* With mmxext only some extended MMX instructions are recognized.
85246c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      The mmxext instructions are MASKMOVQ MOVNTQ PAVGB PAVGW PMAXSW
85256c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      PMAXUB PMINSW PMINUB PMULHUW PSADBW PSHUFW PEXTRW PINSRW PMOVMSKB
85266c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      PREFETCHNTA PREFETCHT0 PREFETCHT1 PREFETCHT2 SFENCE
85276c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
85286c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      http://support.amd.com/us/Embedded_TechDocs/22466.pdf
85296c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      https://en.wikipedia.org/wiki/3DNow!#3DNow.21_extensions */
85306c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
85316c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (archinfo->hwcaps == VEX_HWCAPS_X86_MMXEXT/*integer only sse1 subset*/)
85326c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto mmxext;
85336c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
85349df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj   /* Otherwise we must be doing sse1 or sse2, so we can at least try
85359df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj      for SSE1 here. */
8536c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
8537c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
8538636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
8539129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
8540c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      goto decode_success;
8541c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   }
8542c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
85431e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
85441e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
85451e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      vassert(sz == 4);
8546129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
85471e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      goto decode_success;
85481e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
85491e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
85501e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   /* 0F 55 = ANDNPS -- G = (not G) and E */
8551636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
8552f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_AndV128 );
85531e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      goto decode_success;
85541e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
85551e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
85561e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   /* 0F 54 = ANDPS -- G = G and E */
8557636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
8558f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_AndV128 );
85591e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      goto decode_success;
85601e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
85611e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
85621e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
8563636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
85641e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
85651e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      goto decode_success;
85661e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
85671e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
85681e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
85691e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
85701e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      vassert(sz == 4);
85711e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
85721e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      goto decode_success;
85731e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
8574c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
8575fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 0F 2F = COMISS  -- 32F0x4 comparison G,E, and set ZCP */
8576c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
8577fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
857867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      IRTemp argL = newTemp(Ity_F32);
857967e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      IRTemp argR = newTemp(Ity_F32);
858067e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      modrm = getIByte(delta+2);
858167e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      if (epartIsReg(modrm)) {
858267e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj         assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
858367e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj         delta += 2+1;
8584c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8585c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                  nameXMMReg(gregOfRM(modrm)) );
858667e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      } else {
858767e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
858867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj	 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
858967e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj         delta += 2+alen;
8590c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         DIP("[u]comiss %s,%s\n", dis_buf,
8591c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                  nameXMMReg(gregOfRM(modrm)) );
859267e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      }
859367e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
859467e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj
859567e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
859667e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
859767e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      stmt( IRStmt_Put(
859867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj               OFFB_CC_DEP1,
859967e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj               binop( Iop_And32,
860067e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj                      binop(Iop_CmpF64,
860167e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj                            unop(Iop_F32toF64,mkexpr(argL)),
860267e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj                            unop(Iop_F32toF64,mkexpr(argR))),
860367e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj                      mkU32(0x45)
860467e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj          )));
8605a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      /* Set NDEP even though it isn't used.  This makes redundant-PUT
8606a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj         elimination of previous stores to this field work better. */
8607a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
860867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      goto decode_success;
860967e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   }
8610c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
86114cb918d355cef4e7640d374346852db4556f3524sewardj   /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
86124cb918d355cef4e7640d374346852db4556f3524sewardj      half xmm */
8613fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
86144cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp arg64 = newTemp(Ity_I64);
86154cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp rmode = newTemp(Ity_I32);
86164cb918d355cef4e7640d374346852db4556f3524sewardj      vassert(sz == 4);
86174cb918d355cef4e7640d374346852db4556f3524sewardj
86184cb918d355cef4e7640d374346852db4556f3524sewardj      modrm = getIByte(delta+2);
86194cb918d355cef4e7640d374346852db4556f3524sewardj      if (epartIsReg(modrm)) {
8620a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes         /* Only switch to MMX mode if the source is a MMX register.
8621a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes            See comments on CVTPI2PD for details.  Fixes #357059. */
8622a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes         do_MMX_preamble();
86234cb918d355cef4e7640d374346852db4556f3524sewardj         assign( arg64, getMMXReg(eregOfRM(modrm)) );
86244cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 2+1;
86254cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
86264cb918d355cef4e7640d374346852db4556f3524sewardj                                 nameXMMReg(gregOfRM(modrm)));
86274cb918d355cef4e7640d374346852db4556f3524sewardj      } else {
86284cb918d355cef4e7640d374346852db4556f3524sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
86294cb918d355cef4e7640d374346852db4556f3524sewardj	 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
86304cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 2+alen;
86314cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvtpi2ps %s,%s\n", dis_buf,
86324cb918d355cef4e7640d374346852db4556f3524sewardj                                 nameXMMReg(gregOfRM(modrm)) );
86334cb918d355cef4e7640d374346852db4556f3524sewardj      }
86344cb918d355cef4e7640d374346852db4556f3524sewardj
86354cb918d355cef4e7640d374346852db4556f3524sewardj      assign( rmode, get_sse_roundingmode() );
86364cb918d355cef4e7640d374346852db4556f3524sewardj
86374cb918d355cef4e7640d374346852db4556f3524sewardj      putXMMRegLane32F(
86383bca906f6e715c544eb49c278bedef093c14c0d7sewardj         gregOfRM(modrm), 0,
86393bca906f6e715c544eb49c278bedef093c14c0d7sewardj         binop(Iop_F64toF32,
86404cb918d355cef4e7640d374346852db4556f3524sewardj               mkexpr(rmode),
86416c299f3acab617581ea504e45fbb6cab24c2b29fsewardj               unop(Iop_I32StoF64,
86423bca906f6e715c544eb49c278bedef093c14c0d7sewardj                    unop(Iop_64to32, mkexpr(arg64)) )) );
86434cb918d355cef4e7640d374346852db4556f3524sewardj
86444cb918d355cef4e7640d374346852db4556f3524sewardj      putXMMRegLane32F(
86454cb918d355cef4e7640d374346852db4556f3524sewardj         gregOfRM(modrm), 1,
86463bca906f6e715c544eb49c278bedef093c14c0d7sewardj         binop(Iop_F64toF32,
86474cb918d355cef4e7640d374346852db4556f3524sewardj               mkexpr(rmode),
86486c299f3acab617581ea504e45fbb6cab24c2b29fsewardj               unop(Iop_I32StoF64,
86493bca906f6e715c544eb49c278bedef093c14c0d7sewardj                    unop(Iop_64HIto32, mkexpr(arg64)) )) );
86504cb918d355cef4e7640d374346852db4556f3524sewardj
86514cb918d355cef4e7640d374346852db4556f3524sewardj      goto decode_success;
86524cb918d355cef4e7640d374346852db4556f3524sewardj   }
86534cb918d355cef4e7640d374346852db4556f3524sewardj
86544cb918d355cef4e7640d374346852db4556f3524sewardj   /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
86554cb918d355cef4e7640d374346852db4556f3524sewardj      quarter xmm */
86564cb918d355cef4e7640d374346852db4556f3524sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
86574cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp arg32 = newTemp(Ity_I32);
86584cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp rmode = newTemp(Ity_I32);
86594cb918d355cef4e7640d374346852db4556f3524sewardj      vassert(sz == 4);
86604cb918d355cef4e7640d374346852db4556f3524sewardj
86614cb918d355cef4e7640d374346852db4556f3524sewardj      modrm = getIByte(delta+3);
86624cb918d355cef4e7640d374346852db4556f3524sewardj      if (epartIsReg(modrm)) {
86634cb918d355cef4e7640d374346852db4556f3524sewardj         assign( arg32, getIReg(4, eregOfRM(modrm)) );
86644cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 3+1;
86654cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
86664cb918d355cef4e7640d374346852db4556f3524sewardj                                 nameXMMReg(gregOfRM(modrm)));
86674cb918d355cef4e7640d374346852db4556f3524sewardj      } else {
86684cb918d355cef4e7640d374346852db4556f3524sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
86694cb918d355cef4e7640d374346852db4556f3524sewardj	 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
86704cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 3+alen;
86714cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvtsi2ss %s,%s\n", dis_buf,
86724cb918d355cef4e7640d374346852db4556f3524sewardj                                 nameXMMReg(gregOfRM(modrm)) );
86734cb918d355cef4e7640d374346852db4556f3524sewardj      }
86744cb918d355cef4e7640d374346852db4556f3524sewardj
86754cb918d355cef4e7640d374346852db4556f3524sewardj      assign( rmode, get_sse_roundingmode() );
86764cb918d355cef4e7640d374346852db4556f3524sewardj
86774cb918d355cef4e7640d374346852db4556f3524sewardj      putXMMRegLane32F(
86783bca906f6e715c544eb49c278bedef093c14c0d7sewardj         gregOfRM(modrm), 0,
86793bca906f6e715c544eb49c278bedef093c14c0d7sewardj         binop(Iop_F64toF32,
86803bca906f6e715c544eb49c278bedef093c14c0d7sewardj               mkexpr(rmode),
86816c299f3acab617581ea504e45fbb6cab24c2b29fsewardj               unop(Iop_I32StoF64, mkexpr(arg32)) ) );
86824cb918d355cef4e7640d374346852db4556f3524sewardj
86834cb918d355cef4e7640d374346852db4556f3524sewardj      goto decode_success;
86844cb918d355cef4e7640d374346852db4556f3524sewardj   }
86854cb918d355cef4e7640d374346852db4556f3524sewardj
86864cb918d355cef4e7640d374346852db4556f3524sewardj   /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
86874cb918d355cef4e7640d374346852db4556f3524sewardj      I32 in mmx, according to prevailing SSE rounding mode */
86884cb918d355cef4e7640d374346852db4556f3524sewardj   /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
86894cb918d355cef4e7640d374346852db4556f3524sewardj      I32 in mmx, rounding towards zero */
8690fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
86914cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp dst64  = newTemp(Ity_I64);
86924cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp rmode  = newTemp(Ity_I32);
86934cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp f32lo  = newTemp(Ity_F32);
86944cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp f32hi  = newTemp(Ity_F32);
86952d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool   r2zero = toBool(insn[1] == 0x2C);
86964cb918d355cef4e7640d374346852db4556f3524sewardj
86974cb918d355cef4e7640d374346852db4556f3524sewardj      do_MMX_preamble();
86984cb918d355cef4e7640d374346852db4556f3524sewardj      modrm = getIByte(delta+2);
86994cb918d355cef4e7640d374346852db4556f3524sewardj
87004cb918d355cef4e7640d374346852db4556f3524sewardj      if (epartIsReg(modrm)) {
87014cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 2+1;
87024cb918d355cef4e7640d374346852db4556f3524sewardj	 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
87034cb918d355cef4e7640d374346852db4556f3524sewardj	 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
87044cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
87054cb918d355cef4e7640d374346852db4556f3524sewardj                                   nameXMMReg(eregOfRM(modrm)),
87064cb918d355cef4e7640d374346852db4556f3524sewardj                                   nameMMXReg(gregOfRM(modrm)));
87074cb918d355cef4e7640d374346852db4556f3524sewardj      } else {
87084cb918d355cef4e7640d374346852db4556f3524sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
87094cb918d355cef4e7640d374346852db4556f3524sewardj	 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
87104cb918d355cef4e7640d374346852db4556f3524sewardj	 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
87114cb918d355cef4e7640d374346852db4556f3524sewardj                                              mkexpr(addr),
87124cb918d355cef4e7640d374346852db4556f3524sewardj                                              mkU32(4) )));
87134cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 2+alen;
87144cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
87154cb918d355cef4e7640d374346852db4556f3524sewardj                                   dis_buf,
87164cb918d355cef4e7640d374346852db4556f3524sewardj                                   nameMMXReg(gregOfRM(modrm)));
87174cb918d355cef4e7640d374346852db4556f3524sewardj      }
87184cb918d355cef4e7640d374346852db4556f3524sewardj
87194cb918d355cef4e7640d374346852db4556f3524sewardj      if (r2zero) {
87204cb918d355cef4e7640d374346852db4556f3524sewardj         assign(rmode, mkU32((UInt)Irrm_ZERO) );
87214cb918d355cef4e7640d374346852db4556f3524sewardj      } else {
87224cb918d355cef4e7640d374346852db4556f3524sewardj         assign( rmode, get_sse_roundingmode() );
87234cb918d355cef4e7640d374346852db4556f3524sewardj      }
87244cb918d355cef4e7640d374346852db4556f3524sewardj
87254cb918d355cef4e7640d374346852db4556f3524sewardj      assign(
87264cb918d355cef4e7640d374346852db4556f3524sewardj         dst64,
87274cb918d355cef4e7640d374346852db4556f3524sewardj         binop( Iop_32HLto64,
87286c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                binop( Iop_F64toI32S,
87294cb918d355cef4e7640d374346852db4556f3524sewardj                       mkexpr(rmode),
87304cb918d355cef4e7640d374346852db4556f3524sewardj                       unop( Iop_F32toF64, mkexpr(f32hi) ) ),
87316c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                binop( Iop_F64toI32S,
87324cb918d355cef4e7640d374346852db4556f3524sewardj                       mkexpr(rmode),
87334cb918d355cef4e7640d374346852db4556f3524sewardj                       unop( Iop_F32toF64, mkexpr(f32lo) ) )
87344cb918d355cef4e7640d374346852db4556f3524sewardj              )
87354cb918d355cef4e7640d374346852db4556f3524sewardj      );
87364cb918d355cef4e7640d374346852db4556f3524sewardj
87374cb918d355cef4e7640d374346852db4556f3524sewardj      putMMXReg(gregOfRM(modrm), mkexpr(dst64));
87384cb918d355cef4e7640d374346852db4556f3524sewardj      goto decode_success;
87394cb918d355cef4e7640d374346852db4556f3524sewardj   }
87404cb918d355cef4e7640d374346852db4556f3524sewardj
87414cb918d355cef4e7640d374346852db4556f3524sewardj   /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
87424cb918d355cef4e7640d374346852db4556f3524sewardj      I32 in ireg, according to prevailing SSE rounding mode */
87434cb918d355cef4e7640d374346852db4556f3524sewardj   /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
87440b21044f0cbfd84788247ed7ba65cf77ea832a2csewardj      I32 in ireg, rounding towards zero */
87454cb918d355cef4e7640d374346852db4556f3524sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F
87464cb918d355cef4e7640d374346852db4556f3524sewardj       && (insn[2] == 0x2D || insn[2] == 0x2C)) {
87474cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp rmode = newTemp(Ity_I32);
87484cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp f32lo = newTemp(Ity_F32);
87492d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool   r2zero = toBool(insn[2] == 0x2C);
87504cb918d355cef4e7640d374346852db4556f3524sewardj      vassert(sz == 4);
87514cb918d355cef4e7640d374346852db4556f3524sewardj
87524cb918d355cef4e7640d374346852db4556f3524sewardj      modrm = getIByte(delta+3);
87534cb918d355cef4e7640d374346852db4556f3524sewardj      if (epartIsReg(modrm)) {
87544cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 3+1;
87554cb918d355cef4e7640d374346852db4556f3524sewardj	 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
87564cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
87574cb918d355cef4e7640d374346852db4556f3524sewardj                                   nameXMMReg(eregOfRM(modrm)),
87584cb918d355cef4e7640d374346852db4556f3524sewardj                                   nameIReg(4, gregOfRM(modrm)));
87594cb918d355cef4e7640d374346852db4556f3524sewardj      } else {
87604cb918d355cef4e7640d374346852db4556f3524sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
87614cb918d355cef4e7640d374346852db4556f3524sewardj	 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
87624cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 3+alen;
87634cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
87644cb918d355cef4e7640d374346852db4556f3524sewardj                                   dis_buf,
87654cb918d355cef4e7640d374346852db4556f3524sewardj                                   nameIReg(4, gregOfRM(modrm)));
87664cb918d355cef4e7640d374346852db4556f3524sewardj      }
87674cb918d355cef4e7640d374346852db4556f3524sewardj
87684cb918d355cef4e7640d374346852db4556f3524sewardj      if (r2zero) {
87697df596b1e36840e2d74c90aa55589934add61ccfsewardj         assign( rmode, mkU32((UInt)Irrm_ZERO) );
87704cb918d355cef4e7640d374346852db4556f3524sewardj      } else {
87714cb918d355cef4e7640d374346852db4556f3524sewardj         assign( rmode, get_sse_roundingmode() );
87724cb918d355cef4e7640d374346852db4556f3524sewardj      }
87734cb918d355cef4e7640d374346852db4556f3524sewardj
87744cb918d355cef4e7640d374346852db4556f3524sewardj      putIReg(4, gregOfRM(modrm),
87756c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                 binop( Iop_F64toI32S,
87764cb918d355cef4e7640d374346852db4556f3524sewardj                        mkexpr(rmode),
87774cb918d355cef4e7640d374346852db4556f3524sewardj                        unop( Iop_F32toF64, mkexpr(f32lo) ) )
87784cb918d355cef4e7640d374346852db4556f3524sewardj      );
87794cb918d355cef4e7640d374346852db4556f3524sewardj
87804cb918d355cef4e7640d374346852db4556f3524sewardj      goto decode_success;
87814cb918d355cef4e7640d374346852db4556f3524sewardj   }
87824cb918d355cef4e7640d374346852db4556f3524sewardj
8783176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
8784fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
8785129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
8786176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj      goto decode_success;
8787176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   }
8788176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj
8789176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8790176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
8791176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj      vassert(sz == 4);
8792129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
8793176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj      goto decode_success;
8794176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   }
8795176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj
87967df596b1e36840e2d74c90aa55589934add61ccfsewardj   /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
87977df596b1e36840e2d74c90aa55589934add61ccfsewardj   if (insn[0] == 0x0F && insn[1] == 0xAE
87987df596b1e36840e2d74c90aa55589934add61ccfsewardj       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
87997df596b1e36840e2d74c90aa55589934add61ccfsewardj
88007df596b1e36840e2d74c90aa55589934add61ccfsewardj      IRTemp t64 = newTemp(Ity_I64);
88017df596b1e36840e2d74c90aa55589934add61ccfsewardj      IRTemp ew = newTemp(Ity_I32);
88027df596b1e36840e2d74c90aa55589934add61ccfsewardj
88037df596b1e36840e2d74c90aa55589934add61ccfsewardj      modrm = getIByte(delta+2);
88047df596b1e36840e2d74c90aa55589934add61ccfsewardj      vassert(!epartIsReg(modrm));
88057df596b1e36840e2d74c90aa55589934add61ccfsewardj      vassert(sz == 4);
88067df596b1e36840e2d74c90aa55589934add61ccfsewardj
88077df596b1e36840e2d74c90aa55589934add61ccfsewardj      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
88087df596b1e36840e2d74c90aa55589934add61ccfsewardj      delta += 2+alen;
880933dd31b1bcc175495b96222fa278062fd6116899sewardj      DIP("ldmxcsr %s\n", dis_buf);
88107df596b1e36840e2d74c90aa55589934add61ccfsewardj
88117df596b1e36840e2d74c90aa55589934add61ccfsewardj      /* The only thing we observe in %mxcsr is the rounding mode.
88127df596b1e36840e2d74c90aa55589934add61ccfsewardj         Therefore, pass the 32-bit value (SSE native-format control
88137df596b1e36840e2d74c90aa55589934add61ccfsewardj         word) to a clean helper, getting back a 64-bit value, the
88147df596b1e36840e2d74c90aa55589934add61ccfsewardj         lower half of which is the SSEROUND value to store, and the
88157df596b1e36840e2d74c90aa55589934add61ccfsewardj         upper half of which is the emulation-warning token which may
88167df596b1e36840e2d74c90aa55589934add61ccfsewardj         be generated.
88177df596b1e36840e2d74c90aa55589934add61ccfsewardj      */
88187df596b1e36840e2d74c90aa55589934add61ccfsewardj      /* ULong x86h_check_ldmxcsr ( UInt ); */
88197df596b1e36840e2d74c90aa55589934add61ccfsewardj      assign( t64, mkIRExprCCall(
88207df596b1e36840e2d74c90aa55589934add61ccfsewardj                      Ity_I64, 0/*regparms*/,
88213bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                      "x86g_check_ldmxcsr",
88223bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                      &x86g_check_ldmxcsr,
88237df596b1e36840e2d74c90aa55589934add61ccfsewardj                      mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
88247df596b1e36840e2d74c90aa55589934add61ccfsewardj                   )
88257df596b1e36840e2d74c90aa55589934add61ccfsewardj            );
88267df596b1e36840e2d74c90aa55589934add61ccfsewardj
8827636ad762e49597ef608323f27c7b8eb66962cd90sewardj      put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
88287df596b1e36840e2d74c90aa55589934add61ccfsewardj      assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
88297df596b1e36840e2d74c90aa55589934add61ccfsewardj      put_emwarn( mkexpr(ew) );
88307df596b1e36840e2d74c90aa55589934add61ccfsewardj      /* Finally, if an emulation warning was reported, side-exit to
88317df596b1e36840e2d74c90aa55589934add61ccfsewardj         the next insn, reporting the warning, so that Valgrind's
88327df596b1e36840e2d74c90aa55589934add61ccfsewardj         dispatcher sees the warning. */
88337df596b1e36840e2d74c90aa55589934add61ccfsewardj      stmt(
88347df596b1e36840e2d74c90aa55589934add61ccfsewardj         IRStmt_Exit(
88357df596b1e36840e2d74c90aa55589934add61ccfsewardj            binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
88367df596b1e36840e2d74c90aa55589934add61ccfsewardj            Ijk_EmWarn,
8837c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
8838c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            OFFB_EIP
88397df596b1e36840e2d74c90aa55589934add61ccfsewardj         )
88407df596b1e36840e2d74c90aa55589934add61ccfsewardj      );
88417df596b1e36840e2d74c90aa55589934add61ccfsewardj      goto decode_success;
88427df596b1e36840e2d74c90aa55589934add61ccfsewardj   }
88437df596b1e36840e2d74c90aa55589934add61ccfsewardj
88446c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
88456c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* mmxext sse1 subset starts here. mmxext only arches will parse
88466c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      only this subset of the sse1 instructions. */
88476c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw  mmxext:
88486c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
8849d71ba837242cc470f622335b1c650bce8886a533sewardj   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8850d71ba837242cc470f622335b1c650bce8886a533sewardj   /* 0F F7 = MASKMOVQ -- 8x8 masked store */
8851d71ba837242cc470f622335b1c650bce8886a533sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF7) {
8852d71ba837242cc470f622335b1c650bce8886a533sewardj      Bool ok = False;
8853d71ba837242cc470f622335b1c650bce8886a533sewardj      delta = dis_MMX( &ok, sorb, sz, delta+1 );
8854d71ba837242cc470f622335b1c650bce8886a533sewardj      if (!ok)
8855d71ba837242cc470f622335b1c650bce8886a533sewardj         goto decode_failure;
8856d71ba837242cc470f622335b1c650bce8886a533sewardj      goto decode_success;
8857d71ba837242cc470f622335b1c650bce8886a533sewardj   }
8858d71ba837242cc470f622335b1c650bce8886a533sewardj
88596c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
88606c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F E7 = MOVNTQ -- for us, just a plain MMX store.  Note, the
88616c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      Intel manual does not say anything about the usual business of
88626c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      the FP reg tags getting trashed whenever an MMX insn happens.
88636c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      So we just leave them alone.
88646c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   */
88656c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0xE7) {
88666c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+2);
88676c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (sz == 4 && !epartIsReg(modrm)) {
88686c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         /* do_MMX_preamble(); Intel docs don't specify this */
88696c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
88706c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
88716c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movntq %s,%s\n", dis_buf,
88726c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                               nameMMXReg(gregOfRM(modrm)));
88736c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+alen;
88746c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
88756c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
88766c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* else fall through */
8877176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   }
8878176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj
88796c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
88806c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
88816c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
88826c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
88836c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
88846c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pavgb", False );
8885176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj      goto decode_success;
8886176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   }
8887176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj
88886c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
88896c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
88906c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
88916c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
88926c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
88936c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pavgw", False );
8894176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj      goto decode_success;
8895176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   }
8896176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj
88976c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
88986c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
88996c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      zero-extend of it in ireg(G). */
89006c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0xC5) {
89016c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = insn[2];
89026c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (sz == 4 && epartIsReg(modrm)) {
89036c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         IRTemp sV = newTemp(Ity_I64);
89046c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t5 = newTemp(Ity_I16);
89056c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         do_MMX_preamble();
89066c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign(sV, getMMXReg(eregOfRM(modrm)));
89076c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         breakup64to16s( sV, &t3, &t2, &t1, &t0 );
89086c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         switch (insn[3] & 3) {
89096c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            case 0:  assign(t5, mkexpr(t0)); break;
89106c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            case 1:  assign(t5, mkexpr(t1)); break;
89116c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            case 2:  assign(t5, mkexpr(t2)); break;
89126c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            case 3:  assign(t5, mkexpr(t3)); break;
89136c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            default: vassert(0); /*NOTREACHED*/
89146c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         }
89156c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
89166c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("pextrw $%d,%s,%s\n",
89176c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw             (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
89186c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                           nameIReg(4,gregOfRM(modrm)));
89196c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 4;
89206c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
89216c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
89226c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* else fall through */
8923176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   }
89244cb918d355cef4e7640d374346852db4556f3524sewardj
89256c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
89266c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
89276c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      put it into the specified lane of mmx(G). */
89286c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
89296c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
89306c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         mmx reg.  t4 is the new lane value.  t5 is the original
89316c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         mmx value. t6 is the new mmx value. */
89326c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      Int lane;
89336c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      t4 = newTemp(Ity_I16);
89346c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      t5 = newTemp(Ity_I64);
89356c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      t6 = newTemp(Ity_I64);
89366c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = insn[2];
89376c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
89386c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
89396c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      assign(t5, getMMXReg(gregOfRM(modrm)));
89406c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      breakup64to16s( t5, &t3, &t2, &t1, &t0 );
89416c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
89429636b44102bd3f79cba764576f34931d7b584d9esewardj      if (epartIsReg(modrm)) {
89436c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign(t4, getIReg(2, eregOfRM(modrm)));
89446c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 3+1;
89456c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         lane = insn[3+1-1];
8946b173774421d015736c2316b5e6e998e7de545a5cflorian         DIP("pinsrw $%d,%s,%s\n", lane,
89476c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   nameIReg(2,eregOfRM(modrm)),
89486c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   nameMMXReg(gregOfRM(modrm)));
89499636b44102bd3f79cba764576f34931d7b584d9esewardj      } else {
89509636b44102bd3f79cba764576f34931d7b584d9esewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
89516c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 3+alen;
89526c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         lane = insn[3+alen-1];
89536c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign(t4, loadLE(Ity_I16, mkexpr(addr)));
8954b173774421d015736c2316b5e6e998e7de545a5cflorian         DIP("pinsrw $%d,%s,%s\n", lane,
89556c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   dis_buf,
89566c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   nameMMXReg(gregOfRM(modrm)));
89576c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
89586c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
89596c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      switch (lane & 3) {
89606c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 0:  assign(t6, mk64from16s(t3,t2,t1,t4)); break;
89616c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 1:  assign(t6, mk64from16s(t3,t2,t4,t0)); break;
89626c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 2:  assign(t6, mk64from16s(t3,t4,t1,t0)); break;
89636c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 3:  assign(t6, mk64from16s(t4,t2,t1,t0)); break;
89646c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         default: vassert(0); /*NOTREACHED*/
89659636b44102bd3f79cba764576f34931d7b584d9esewardj      }
89666c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      putMMXReg(gregOfRM(modrm), mkexpr(t6));
89679636b44102bd3f79cba764576f34931d7b584d9esewardj      goto decode_success;
89689636b44102bd3f79cba764576f34931d7b584d9esewardj   }
89699636b44102bd3f79cba764576f34931d7b584d9esewardj
89706c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
89716c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F EE = PMAXSW -- 16x4 signed max */
89726c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
89736c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
89746c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
89756c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pmaxsw", False );
89766c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
897709f415512b3b874475a4ec78e15cf87712b49b7bsewardj   }
897809f415512b3b874475a4ec78e15cf87712b49b7bsewardj
89796c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
89806c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F DE = PMAXUB -- 8x8 unsigned max */
89816c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
89826c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
89836c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
89846c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pmaxub", False );
89850bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      goto decode_success;
89860bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
89870bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
89886c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
89896c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F EA = PMINSW -- 16x4 signed min */
89906c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
89916c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
89926c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
89936c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pminsw", False );
89946c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
89950bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
89960bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
89976c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
89986c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F DA = PMINUB -- 8x8 unsigned min */
89996c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
90006c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
90016c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
90026c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pminub", False );
90030bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      goto decode_success;
90040bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
90050bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
90066c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
90076c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
90086c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      mmx(E), turn them into a byte, and put zero-extend of it in
90096c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      ireg(G). */
90106c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
90116c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = insn[2];
90126c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (epartIsReg(modrm)) {
90136c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         do_MMX_preamble();
90146c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t0 = newTemp(Ity_I64);
90156c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t1 = newTemp(Ity_I32);
90166c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign(t0, getMMXReg(eregOfRM(modrm)));
90176c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign(t1, unop(Iop_8Uto32, unop(Iop_GetMSBs8x8, mkexpr(t0))));
90186c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putIReg(4, gregOfRM(modrm), mkexpr(t1));
90196c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
90206c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                 nameIReg(4,gregOfRM(modrm)));
90216c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 3;
90220bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj         goto decode_success;
90236c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
90240bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      /* else fall through */
90250bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
90260bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
90276c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
90286c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
90296c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
90306c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
90316c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
90326c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pmuluh", False );
90336c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
90349636b44102bd3f79cba764576f34931d7b584d9esewardj   }
90359636b44102bd3f79cba764576f34931d7b584d9esewardj
90366c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
90376c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 18 /1 = PREFETCH0   -- with various different hints */
90386c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 18 /2 = PREFETCH1 */
90396c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 18 /3 = PREFETCH2 */
90406c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0x18
90416c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw       && !epartIsReg(insn[2])
90426c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw       && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
90436c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      const HChar* hintstr = "??";
90446c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90459636b44102bd3f79cba764576f34931d7b584d9esewardj      modrm = getIByte(delta+2);
90466c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(!epartIsReg(modrm));
90476c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90486c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
90496c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta += 2+alen;
90506c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90516c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      switch (gregOfRM(modrm)) {
90526c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 0: hintstr = "nta"; break;
90536c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 1: hintstr = "t0"; break;
90546c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 2: hintstr = "t1"; break;
90556c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 3: hintstr = "t2"; break;
90566c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         default: vassert(0); /*NOTREACHED*/
90579636b44102bd3f79cba764576f34931d7b584d9esewardj      }
90586c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90596c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      DIP("prefetch%s %s\n", hintstr, dis_buf);
90606c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
90619636b44102bd3f79cba764576f34931d7b584d9esewardj   }
90629636b44102bd3f79cba764576f34931d7b584d9esewardj
90636c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 0D /0 = PREFETCH  m8 -- 3DNow! prefetch */
90646c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 0D /1 = PREFETCHW m8 -- ditto, with some other hint */
90656c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0x0D
90666c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw       && !epartIsReg(insn[2])
90676c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw       && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 1) {
90686c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      const HChar* hintstr = "??";
90696c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90709636b44102bd3f79cba764576f34931d7b584d9esewardj      modrm = getIByte(delta+2);
90716c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(!epartIsReg(modrm));
90726c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90736c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
90746c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta += 2+alen;
90756c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90766c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      switch (gregOfRM(modrm)) {
90776c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 0: hintstr = ""; break;
90786c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 1: hintstr = "w"; break;
90796c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         default: vassert(0); /*NOTREACHED*/
90809636b44102bd3f79cba764576f34931d7b584d9esewardj      }
90816c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90826c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      DIP("prefetch%s %s\n", hintstr, dis_buf);
90836c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
90849636b44102bd3f79cba764576f34931d7b584d9esewardj   }
90859636b44102bd3f79cba764576f34931d7b584d9esewardj
90866c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
90876c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
90886c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF6) {
90896c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
90906c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
90916c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                 sorb, delta+2, insn[1], "psadbw", False );
90929636b44102bd3f79cba764576f34931d7b584d9esewardj      goto decode_success;
90939636b44102bd3f79cba764576f34931d7b584d9esewardj   }
90949636b44102bd3f79cba764576f34931d7b584d9esewardj
90956c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
90966c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
90976c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
90986c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      Int order;
90996c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      IRTemp sV, dV, s3, s2, s1, s0;
91006c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      s3 = s2 = s1 = s0 = IRTemp_INVALID;
91016c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      sV = newTemp(Ity_I64);
91026c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      dV = newTemp(Ity_I64);
91036c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
91046c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = insn[2];
91059636b44102bd3f79cba764576f34931d7b584d9esewardj      if (epartIsReg(modrm)) {
91066c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign( sV, getMMXReg(eregOfRM(modrm)) );
91076c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         order = (Int)insn[3];
91086c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+2;
91096c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("pshufw $%d,%s,%s\n", order,
91106c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   nameMMXReg(eregOfRM(modrm)),
91116c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   nameMMXReg(gregOfRM(modrm)));
91129636b44102bd3f79cba764576f34931d7b584d9esewardj      } else {
91136c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
91146c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
91156c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw	 order = (Int)insn[2+alen];
91169636b44102bd3f79cba764576f34931d7b584d9esewardj         delta += 3+alen;
91176c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("pshufw $%d,%s,%s\n", order,
91186c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   dis_buf,
91196c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   nameMMXReg(gregOfRM(modrm)));
91209636b44102bd3f79cba764576f34931d7b584d9esewardj      }
91216c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      breakup64to16s( sV, &s3, &s2, &s1, &s0 );
91229636b44102bd3f79cba764576f34931d7b584d9esewardj
91236c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw#     define SEL(n) \
91246c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
91256c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      assign(dV,
91266c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
91276c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          SEL((order>>2)&3), SEL((order>>0)&3) )
91286c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      );
91296c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      putMMXReg(gregOfRM(modrm), mkexpr(dV));
91306c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw#     undef SEL
91319636b44102bd3f79cba764576f34931d7b584d9esewardj      goto decode_success;
91329636b44102bd3f79cba764576f34931d7b584d9esewardj   }
91339636b44102bd3f79cba764576f34931d7b584d9esewardj
91346c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F AE /7 = SFENCE -- flush pending operations to memory */
91356c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0xAE
91366c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw       && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
91379636b44102bd3f79cba764576f34931d7b584d9esewardj      vassert(sz == 4);
91386c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta += 3;
91396c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* Insert a memory fence.  It's sometimes important that these
91406c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         are carried through to the generated code. */
91416c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      stmt( IRStmt_MBE(Imbe_Fence) );
91426c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      DIP("sfence\n");
91439636b44102bd3f79cba764576f34931d7b584d9esewardj      goto decode_success;
91449636b44102bd3f79cba764576f34931d7b584d9esewardj   }
91459636b44102bd3f79cba764576f34931d7b584d9esewardj
91466c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* End of mmxext sse1 subset. No more sse parsing for mmxext only arches. */
91476c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (archinfo->hwcaps == VEX_HWCAPS_X86_MMXEXT/*integer only sse1 subset*/)
91486c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto after_sse_decoders;
91496c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
91506c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
91516c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
91526c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
91536c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
91549636b44102bd3f79cba764576f34931d7b584d9esewardj      goto decode_success;
91559636b44102bd3f79cba764576f34931d7b584d9esewardj   }
91569636b44102bd3f79cba764576f34931d7b584d9esewardj
91576c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
91586c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
91596c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(sz == 4);
91606c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
9161b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      goto decode_success;
9162b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9163b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
91646c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
91656c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
91666c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
9167b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      goto decode_success;
9168b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9169b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
91706c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
91716c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
91726c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(sz == 4);
91736c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
91746c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
9175b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9176b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
91776c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
91786c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
91796c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
91806c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+2);
9181e5854d6d470f21677ec84f71d09129434b044246sewardj      if (epartIsReg(modrm)) {
91826c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMReg( gregOfRM(modrm),
91836c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                    getXMMReg( eregOfRM(modrm) ));
91846c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
91856c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                  nameXMMReg(gregOfRM(modrm)));
91866c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+1;
9187e5854d6d470f21677ec84f71d09129434b044246sewardj      } else {
91887420b0969284c2e6d7421204d29b1bc2b1234ed6sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
91896c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         if (insn[1] == 0x28/*movaps*/)
91906c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            gen_SEGV_if_not_16_aligned( addr );
91916c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMReg( gregOfRM(modrm),
91926c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                    loadLE(Ity_V128, mkexpr(addr)) );
91936c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("mov[ua]ps %s,%s\n", dis_buf,
91946c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                  nameXMMReg(gregOfRM(modrm)));
91956c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+alen;
9196b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      }
9197e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
9198b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9199b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
92006c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
92016c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
92026c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F
92036c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw       && (insn[1] == 0x29 || insn[1] == 0x11)) {
92046c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+2);
92056c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (epartIsReg(modrm)) {
92066c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         /* fall through; awaiting test case */
92076c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      } else {
92086c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
92096c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         if (insn[1] == 0x29/*movaps*/)
92106c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            gen_SEGV_if_not_16_aligned( addr );
92116c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
92126c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRM(modrm)),
92136c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                  dis_buf );
92146c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+alen;
92156c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
92166c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
92173bca906f6e715c544eb49c278bedef093c14c0d7sewardj   }
92183bca906f6e715c544eb49c278bedef093c14c0d7sewardj
92196c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
92206c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
92216c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
92226c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+2);
92236c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (epartIsReg(modrm)) {
92246c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+1;
92256c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
92266c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          getXMMRegLane64( eregOfRM(modrm), 0 ) );
92276c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
92286c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                               nameXMMReg(gregOfRM(modrm)));
92296c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      } else {
92306c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
92316c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+alen;
92326c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
92336c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          loadLE(Ity_I64, mkexpr(addr)) );
92346c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movhps %s,%s\n", dis_buf,
92356c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                               nameXMMReg( gregOfRM(modrm) ));
92366c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
9237b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      goto decode_success;
9238b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9239b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
92406c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
92416c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
92426c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (!epartIsReg(insn[2])) {
92436c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2;
92446c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta, dis_buf );
92456c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += alen;
92466c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         storeLE( mkexpr(addr),
92476c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                  getXMMRegLane64( gregOfRM(insn[2]),
92486c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   1/*upper lane*/ ) );
92496c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
92506c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                               dis_buf);
92516c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
92526c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
92536c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* else fall through */
9254b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9255b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
92566c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
92576c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
92586c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
92596c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+2);
92606c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (epartIsReg(modrm)) {
92616c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+1;
92626c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane64( gregOfRM(modrm),
92636c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          0/*lower lane*/,
92646c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          getXMMRegLane64( eregOfRM(modrm), 1 ));
92656c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
92666c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                 nameXMMReg(gregOfRM(modrm)));
92676c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      } else {
92686c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
92696c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+alen;
92706c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane64( gregOfRM(modrm),  0/*lower lane*/,
92716c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          loadLE(Ity_I64, mkexpr(addr)) );
92726c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movlps %s, %s\n",
92736c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw             dis_buf, nameXMMReg( gregOfRM(modrm) ));
92746c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
9275b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      goto decode_success;
9276b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9277b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
92786c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
92796c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
92806c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (!epartIsReg(insn[2])) {
92816c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2;
92826c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta, dis_buf );
92836c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += alen;
92846c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         storeLE( mkexpr(addr),
92856c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                  getXMMRegLane64( gregOfRM(insn[2]),
92866c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   0/*lower lane*/ ) );
92876c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
92886c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                dis_buf);
9289b54520819b40c3fe907725b56bcd8db5112c0b9asewardj         goto decode_success;
92906c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
9291b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      /* else fall through */
9292b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9293b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
92946c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
92956c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      to 4 lowest bits of ireg(G) */
92966c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0x50) {
92977df596b1e36840e2d74c90aa55589934add61ccfsewardj      modrm = getIByte(delta+2);
92986c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (sz == 4 && epartIsReg(modrm)) {
92996c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         Int src;
93006c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t0 = newTemp(Ity_I32);
93016c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t1 = newTemp(Ity_I32);
93026c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t2 = newTemp(Ity_I32);
93036c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t3 = newTemp(Ity_I32);
93046c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+1;
93056c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         src = eregOfRM(modrm);
93066c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign( t0, binop( Iop_And32,
93076c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
93086c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            mkU32(1) ));
93096c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign( t1, binop( Iop_And32,
93106c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
93116c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            mkU32(2) ));
93126c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign( t2, binop( Iop_And32,
93136c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
93146c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            mkU32(4) ));
93156c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign( t3, binop( Iop_And32,
93166c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
93176c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            mkU32(8) ));
93186c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putIReg(4, gregOfRM(modrm),
93196c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                    binop(Iop_Or32,
93206c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
93216c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
93226c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                         )
93236c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                 );
93246c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movmskps %s,%s\n", nameXMMReg(src),
93256c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                 nameIReg(4, gregOfRM(modrm)));
93266c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
93277df596b1e36840e2d74c90aa55589934add61ccfsewardj      }
93286c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* else fall through */
93297df596b1e36840e2d74c90aa55589934add61ccfsewardj   }
93307df596b1e36840e2d74c90aa55589934add61ccfsewardj
93316c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
93326c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
93336c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0x2B) {
93348531768c63e46cf1ab91c20d604b05d9f90abddfsewardj      modrm = getIByte(delta+2);
93356c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (!epartIsReg(modrm)) {
93366c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
93376c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         gen_SEGV_if_not_16_aligned( addr );
93386c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
93396c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
93406c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                 dis_buf,
93416c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                 nameXMMReg(gregOfRM(modrm)));
93426c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+alen;
93436c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
93448531768c63e46cf1ab91c20d604b05d9f90abddfsewardj      }
93456c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* else fall through */
93468531768c63e46cf1ab91c20d604b05d9f90abddfsewardj   }
93478531768c63e46cf1ab91c20d604b05d9f90abddfsewardj
93486c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
93496c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      (lo 1/4 xmm).  If E is mem, upper 3/4 of G is zeroed out. */
93506c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
93516c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(sz == 4);
93526c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+3);
93536c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (epartIsReg(modrm)) {
93546c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane32( gregOfRM(modrm), 0,
93556c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          getXMMRegLane32( eregOfRM(modrm), 0 ));
93566c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
93576c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                              nameXMMReg(gregOfRM(modrm)));
93586c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 3+1;
93596c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      } else {
93606c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
93616c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         /* zero bits 127:64 */
93626c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
93636c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         /* zero bits 63:32 */
93646c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane32( gregOfRM(modrm), 1, mkU32(0) );
93656c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         /* write bits 31:0 */
93666c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane32( gregOfRM(modrm), 0,
93676c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          loadLE(Ity_I32, mkexpr(addr)) );
93686c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movss %s,%s\n", dis_buf,
93696c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                              nameXMMReg(gregOfRM(modrm)));
93706c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 3+alen;
93716c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
93720bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      goto decode_success;
93730bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
93740bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
93756c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
93766c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      or lo 1/4 xmm). */
93776c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
93786c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(sz == 4);
93796c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+3);
93800bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      if (epartIsReg(modrm)) {
93816c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         /* fall through, we don't yet have a test case */
93820bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      } else {
93836c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
93846c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         storeLE( mkexpr(addr),
93856c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                  getXMMRegLane32(gregOfRM(modrm), 0) );
93866c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)),
93876c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                              dis_buf);
93880bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj         delta += 3+alen;
93896c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
93900bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      }
93916c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   }
93920bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
93936c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
93946c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
93956c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
93966c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
93976c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   }
93986c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
93996c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
94006c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
94016c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(sz == 4);
94026c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
94036c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
94046c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   }
94056c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
94066c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 56 = ORPS -- G = G and E */
94076c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
94086c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_OrV128 );
94090bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      goto decode_success;
94100bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
94110bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
94120bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
94130bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   if (insn[0] == 0x0F && insn[1] == 0x53) {
94140bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      vassert(sz == 4);
9415129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
94161ddee21008ffdb2ac7f8e6a73445f150f753606fsewardj                                        "rcpps", Iop_RecipEst32Fx4 );
94170bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      goto decode_success;
94180bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
94190bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
94200bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
94210bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
94220bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      vassert(sz == 4);
9423129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
94241ddee21008ffdb2ac7f8e6a73445f150f753606fsewardj                                         "rcpss", Iop_RecipEst32F0x4 );
94250bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      goto decode_success;
94260bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
9427b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
9428c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
9429c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   if (insn[0] == 0x0F && insn[1] == 0x52) {
9430c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      vassert(sz == 4);
9431c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
94321ddee21008ffdb2ac7f8e6a73445f150f753606fsewardj                                        "rsqrtps", Iop_RSqrtEst32Fx4 );
9433c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9434c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9435c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9436c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
9437c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
9438c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      vassert(sz == 4);
9439c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
94401ddee21008ffdb2ac7f8e6a73445f150f753606fsewardj                                         "rsqrtss", Iop_RSqrtEst32F0x4 );
9441c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9442c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9443c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9444c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
9445008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
9446c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      Int    select;
9447c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      IRTemp sV, dV;
9448c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9449c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      sV = newTemp(Ity_V128);
9450c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      dV = newTemp(Ity_V128);
9451c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9452c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      modrm = insn[2];
9453c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
9454c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9455c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      if (epartIsReg(modrm)) {
9456c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
9457c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         select = (Int)insn[3];
9458c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         delta += 2+2;
9459c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         DIP("shufps $%d,%s,%s\n", select,
9460c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                   nameXMMReg(eregOfRM(modrm)),
9461c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                   nameXMMReg(gregOfRM(modrm)));
9462c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      } else {
9463c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9464c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9465c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         select = (Int)insn[2+alen];
9466c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         delta += 3+alen;
9467c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         DIP("shufps $%d,%s,%s\n", select,
9468c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                   dis_buf,
9469c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                   nameXMMReg(gregOfRM(modrm)));
9470c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      }
9471c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9472c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9473c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9474c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9475c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj#     define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
9476c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj#     define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9477c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9478c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      putXMMReg(
9479c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         gregOfRM(modrm),
9480c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
9481c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                       SELD((select>>2)&3), SELD((select>>0)&3) )
9482c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      );
9483c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9484c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj#     undef SELD
9485c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj#     undef SELS
9486c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9487c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9488c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9489c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9490c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
9491008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
9492c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9493c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                        "sqrtps", Iop_Sqrt32Fx4 );
9494c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9495c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9496c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9497c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9498c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
9499c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      vassert(sz == 4);
9500c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9501c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                         "sqrtss", Iop_Sqrt32F0x4 );
9502c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9503c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9504c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9505a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
95067df596b1e36840e2d74c90aa55589934add61ccfsewardj   if (insn[0] == 0x0F && insn[1] == 0xAE
95077df596b1e36840e2d74c90aa55589934add61ccfsewardj       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
95087df596b1e36840e2d74c90aa55589934add61ccfsewardj      modrm = getIByte(delta+2);
95097df596b1e36840e2d74c90aa55589934add61ccfsewardj      vassert(sz == 4);
95107df596b1e36840e2d74c90aa55589934add61ccfsewardj      vassert(!epartIsReg(modrm));
95117df596b1e36840e2d74c90aa55589934add61ccfsewardj
95127df596b1e36840e2d74c90aa55589934add61ccfsewardj      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
95137df596b1e36840e2d74c90aa55589934add61ccfsewardj      delta += 2+alen;
95147df596b1e36840e2d74c90aa55589934add61ccfsewardj
95157df596b1e36840e2d74c90aa55589934add61ccfsewardj      /* Fake up a native SSE mxcsr word.  The only thing it depends
95167df596b1e36840e2d74c90aa55589934add61ccfsewardj         on is SSEROUND[1:0], so call a clean helper to cook it up.
95177df596b1e36840e2d74c90aa55589934add61ccfsewardj      */
95187df596b1e36840e2d74c90aa55589934add61ccfsewardj      /* UInt x86h_create_mxcsr ( UInt sseround ) */
951933dd31b1bcc175495b96222fa278062fd6116899sewardj      DIP("stmxcsr %s\n", dis_buf);
95207df596b1e36840e2d74c90aa55589934add61ccfsewardj      storeLE( mkexpr(addr),
95217df596b1e36840e2d74c90aa55589934add61ccfsewardj               mkIRExprCCall(
95227df596b1e36840e2d74c90aa55589934add61ccfsewardj                  Ity_I32, 0/*regp*/,
95233bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                  "x86g_create_mxcsr", &x86g_create_mxcsr,
9524a0e83b06f304527e3e9aec527c344e35e7023d76sewardj                  mkIRExprVec_1( get_sse_roundingmode() )
95257df596b1e36840e2d74c90aa55589934add61ccfsewardj               )
95267df596b1e36840e2d74c90aa55589934add61ccfsewardj             );
95277df596b1e36840e2d74c90aa55589934add61ccfsewardj      goto decode_success;
95287df596b1e36840e2d74c90aa55589934add61ccfsewardj   }
95297df596b1e36840e2d74c90aa55589934add61ccfsewardj
9530c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
9531008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
9532c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
9533c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9534c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9535c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9536008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
9537c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
9538c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      vassert(sz == 4);
9539c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
9540c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9541c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9542c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9543c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9544c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9545c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* These just appear to be special cases of SHUFPS */
9546008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9547c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      IRTemp sV, dV;
9548c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
95492d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool hi = toBool(insn[1] == 0x15);
9550c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      sV = newTemp(Ity_V128);
9551c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      dV = newTemp(Ity_V128);
9552c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9553c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      modrm = insn[2];
9554c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
9555c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9556c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      if (epartIsReg(modrm)) {
9557c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
9558c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         delta += 2+1;
9559c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9560c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                  nameXMMReg(eregOfRM(modrm)),
9561c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                  nameXMMReg(gregOfRM(modrm)));
9562c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      } else {
9563c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9564c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9565c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         delta += 2+alen;
9566c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9567c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                  dis_buf,
9568c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                  nameXMMReg(gregOfRM(modrm)));
9569c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      }
9570c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9571c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9572c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9573c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9574c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      if (hi) {
9575c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
9576c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      } else {
9577c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
9578c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      }
9579c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9580c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9581c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9582c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9583c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 57 = XORPS -- G = G and E */
9584008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
9585f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_XorV128 );
9586c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9587c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9588c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9589636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* ---------------------------------------------------- */
9590636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* --- end of the SSE decoder.                      --- */
9591636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* ---------------------------------------------------- */
9592636ad762e49597ef608323f27c7b8eb66962cd90sewardj
9593636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* ---------------------------------------------------- */
9594636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* --- start of the SSE2 decoder.                   --- */
9595636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* ---------------------------------------------------- */
9596636ad762e49597ef608323f27c7b8eb66962cd90sewardj
95979df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj   /* Skip parts of the decoder which don't apply given the stated
95989df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj      guest subarchitecture. */
95995117ce116f47141cb23d1b49cc826e19323add97sewardj   if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
96005117ce116f47141cb23d1b49cc826e19323add97sewardj      goto after_sse_decoders; /* no SSE2 capabilities */
96019df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj
96028462d113e3efeacceb304222dada8d85f748295aflorian   insn = &guest_code[delta];
9603636ad762e49597ef608323f27c7b8eb66962cd90sewardj
9604636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9605636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
9606636ad762e49597ef608323f27c7b8eb66962cd90sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
9607636ad762e49597ef608323f27c7b8eb66962cd90sewardj      goto decode_success;
9608636ad762e49597ef608323f27c7b8eb66962cd90sewardj   }
9609636ad762e49597ef608323f27c7b8eb66962cd90sewardj
9610636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9611636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
9612636ad762e49597ef608323f27c7b8eb66962cd90sewardj      vassert(sz == 4);
9613636ad762e49597ef608323f27c7b8eb66962cd90sewardj      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
9614636ad762e49597ef608323f27c7b8eb66962cd90sewardj      goto decode_success;
9615636ad762e49597ef608323f27c7b8eb66962cd90sewardj   }
9616636ad762e49597ef608323f27c7b8eb66962cd90sewardj
9617636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9618636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
9619f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_AndV128 );
9620636ad762e49597ef608323f27c7b8eb66962cd90sewardj      goto decode_success;
9621636ad762e49597ef608323f27c7b8eb66962cd90sewardj   }
9622636ad762e49597ef608323f27c7b8eb66962cd90sewardj
9623636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* 66 0F 54 = ANDPD -- G = G and E */
9624636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
9625f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_AndV128 );
9626636ad762e49597ef608323f27c7b8eb66962cd90sewardj      goto decode_success;
9627636ad762e49597ef608323f27c7b8eb66962cd90sewardj   }
9628636ad762e49597ef608323f27c7b8eb66962cd90sewardj
9629fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9630fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
9631fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
9632fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9633fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9634fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9635fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9636fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
9637fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
9638fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
9639fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9640fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9641fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9642fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 2F = COMISD  -- 64F0x2 comparison G,E, and set ZCP */
9643fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
9644fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9645fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argL = newTemp(Ity_F64);
9646fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argR = newTemp(Ity_F64);
9647fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9648fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9649fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
9650fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9651fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9652fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                  nameXMMReg(gregOfRM(modrm)) );
9653fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9654fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9655fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9656fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9657fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("[u]comisd %s,%s\n", dis_buf,
9658fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                  nameXMMReg(gregOfRM(modrm)) );
9659fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9660fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
9661fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9662fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
9663fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
9664fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      stmt( IRStmt_Put(
9665fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj               OFFB_CC_DEP1,
9666fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj               binop( Iop_And32,
9667fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                      binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
9668fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                      mkU32(0x45)
9669fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj          )));
9670a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      /* Set NDEP even though it isn't used.  This makes redundant-PUT
9671a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj         elimination of previous stores to this field work better. */
9672a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
9673fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9674fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9675fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9676fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9677fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      F64 in xmm(G) */
9678fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
9679fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp arg64 = newTemp(Ity_I64);
9680fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
9681fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9682fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
9683fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9684fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
9685fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
9686fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9687fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9688fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9689fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9690fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9691fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
9692fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtdq2pd %s,%s\n", dis_buf,
9693fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9694fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9695fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9696fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F(
9697fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         gregOfRM(modrm), 0,
96986c299f3acab617581ea504e45fbb6cab24c2b29fsewardj         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)))
9699fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      );
9700fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9701fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F(
9702fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         gregOfRM(modrm), 1,
97036c299f3acab617581ea504e45fbb6cab24c2b29fsewardj         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)))
9704fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      );
9705fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9706fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9707fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9708fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9709fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9710fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      xmm(G) */
9711fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
9712fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argV  = newTemp(Ity_V128);
9713fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
9714fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9715fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9716fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9717fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argV, getXMMReg(eregOfRM(modrm)) );
9718fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9719fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9720fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9721fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9722fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9723fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9724fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9725fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtdq2ps %s,%s\n", dis_buf,
9726fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9727fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9728fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9729fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, get_sse_roundingmode() );
9730fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9731fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9732fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     define CVT(_t)  binop( Iop_F64toF32,                    \
9733fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(rmode),                   \
97346c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                             unop(Iop_I32StoF64,mkexpr(_t)))
9735fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9736fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
9737fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
9738fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9739fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9740fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9741fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     undef CVT
9742fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9743fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9744fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9745fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9746fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9747fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      lo half xmm(G), and zero upper half */
9748fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
9749fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argV  = newTemp(Ity_V128);
9750fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
9751fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
9752fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9753fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
9754fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9755fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argV, getXMMReg(eregOfRM(modrm)) );
9756fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
9757fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9758fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9759fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9760fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9761fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9762fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
9763fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtpd2dq %s,%s\n", dis_buf,
9764fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9765fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9766fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9767fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, get_sse_roundingmode() );
9768fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      t0 = newTemp(Ity_F64);
9769fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      t1 = newTemp(Ity_F64);
9770fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( t0, unop(Iop_ReinterpI64asF64,
9771f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                       unop(Iop_V128to64, mkexpr(argV))) );
9772fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( t1, unop(Iop_ReinterpI64asF64,
9773f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                       unop(Iop_V128HIto64, mkexpr(argV))) );
9774fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
97756c299f3acab617581ea504e45fbb6cab24c2b29fsewardj#     define CVT(_t)  binop( Iop_F64toI32S,                   \
9776fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(rmode),                   \
9777fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(_t) )
9778fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9779fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9780fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9781fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9782fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9783fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9784fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     undef CVT
9785fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9786fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9787fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9788fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9789fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9790fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      I32 in mmx, according to prevailing SSE rounding mode */
9791fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9792fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      I32 in mmx, rounding towards zero */
9793fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9794fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp dst64  = newTemp(Ity_I64);
9795fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode  = newTemp(Ity_I32);
9796fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f64lo  = newTemp(Ity_F64);
9797fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f64hi  = newTemp(Ity_F64);
97982d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool   r2zero = toBool(insn[1] == 0x2C);
9799fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9800fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      do_MMX_preamble();
9801fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9802fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9803fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9804fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9805fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9806fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
9807fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9808fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   nameXMMReg(eregOfRM(modrm)),
9809fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   nameMMXReg(gregOfRM(modrm)));
9810fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9811fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9812fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9813fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
9814fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                              mkexpr(addr),
9815fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                              mkU32(8) )));
9816fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9817fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9818fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   dis_buf,
9819fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   nameMMXReg(gregOfRM(modrm)));
9820fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9821fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9822fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (r2zero) {
9823fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign(rmode, mkU32((UInt)Irrm_ZERO) );
9824fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9825fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( rmode, get_sse_roundingmode() );
9826fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9827fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9828fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign(
9829fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         dst64,
9830fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         binop( Iop_32HLto64,
98316c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64hi) ),
98326c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo) )
9833fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj              )
9834fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      );
9835fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9836fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putMMXReg(gregOfRM(modrm), mkexpr(dst64));
9837fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9838fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9839fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9840fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9841fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      lo half xmm(G), and zero upper half */
9842fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* Note, this is practically identical to CVTPD2DQ.  It would have
9843fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      been nicer to merge them together, but the insn[] offsets differ
9844fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      by one. */
9845fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
9846fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argV  = newTemp(Ity_V128);
9847fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
9848fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9849fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9850fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9851fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argV, getXMMReg(eregOfRM(modrm)) );
9852fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9853fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9854fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9855fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9856fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9857fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9858fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9859fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtpd2ps %s,%s\n", dis_buf,
9860fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9861fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9862fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9863fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, get_sse_roundingmode() );
9864fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      t0 = newTemp(Ity_F64);
9865fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      t1 = newTemp(Ity_F64);
9866fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( t0, unop(Iop_ReinterpI64asF64,
9867f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                       unop(Iop_V128to64, mkexpr(argV))) );
9868fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( t1, unop(Iop_ReinterpI64asF64,
9869f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                       unop(Iop_V128HIto64, mkexpr(argV))) );
9870fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9871fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     define CVT(_t)  binop( Iop_F64toF32,                    \
9872fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(rmode),                   \
9873fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(_t) )
9874fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9875fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32(  gregOfRM(modrm), 3, mkU32(0) );
9876fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32(  gregOfRM(modrm), 2, mkU32(0) );
9877fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9878fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9879fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9880fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     undef CVT
9881fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9882fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9883fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9884fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9885fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9886fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      xmm(G) */
9887fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
9888fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp arg64 = newTemp(Ity_I64);
9889fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9890fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9891fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
989230a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj         /* Only switch to MMX mode if the source is a MMX register.
989330a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj            This is inconsistent with all other instructions which
989430a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj            convert between XMM and (M64 or MMX), which always switch
989530a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj            to MMX mode even if 64-bit operand is M64 and not MMX.  At
989630a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj            least, that's what the Intel docs seem to me to say.
989730a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj            Fixes #210264. */
989830a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj         do_MMX_preamble();
9899fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( arg64, getMMXReg(eregOfRM(modrm)) );
9900fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9901fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9902fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9903fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9904fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9905fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9906fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9907fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtpi2pd %s,%s\n", dis_buf,
9908fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9909fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9910fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9911fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F(
9912fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         gregOfRM(modrm), 0,
99136c299f3acab617581ea504e45fbb6cab24c2b29fsewardj         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)) )
9914fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      );
9915fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9916fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F(
9917fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         gregOfRM(modrm), 1,
99186c299f3acab617581ea504e45fbb6cab24c2b29fsewardj         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)) )
9919fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      );
9920fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9921fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9922fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9923fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9924fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9925fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      xmm(G) */
9926fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
9927fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argV  = newTemp(Ity_V128);
9928fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
9929fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9930fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9931fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9932fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argV, getXMMReg(eregOfRM(modrm)) );
9933fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9934fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9935fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9936fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9937fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9938fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9939fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9940fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtps2dq %s,%s\n", dis_buf,
9941fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9942fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9943fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9944fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, get_sse_roundingmode() );
9945fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9946fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9947fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      /* This is less than ideal.  If it turns out to be a performance
9948fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 bottleneck it can be improved. */
9949fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     define CVT(_t)                            \
99506c299f3acab617581ea504e45fbb6cab24c2b29fsewardj        binop( Iop_F64toI32S,                   \
9951fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj               mkexpr(rmode),                   \
9952fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj               unop( Iop_F32toF64,              \
9953fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                     unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9954fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9955fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9956fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9957fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9958fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9959fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9960fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     undef CVT
9961fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9962fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9963fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9964fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9965fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9966fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      F64 in xmm(G). */
9967fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
9968fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f32lo = newTemp(Ity_F32);
9969fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f32hi = newTemp(Ity_F32);
9970fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9971fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9972fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9973fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
9974fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
9975fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9976fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9977fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9978fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9979fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9980fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9981fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( f32hi, loadLE(Ity_F32,
9982fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                               binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
9983fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9984fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtps2pd %s,%s\n", dis_buf,
9985fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9986fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9987fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9988fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F( gregOfRM(modrm), 1,
9989fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                        unop(Iop_F32toF64, mkexpr(f32hi)) );
9990fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F( gregOfRM(modrm), 0,
9991fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                        unop(Iop_F32toF64, mkexpr(f32lo)) );
9992fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9993fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9994fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9995fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9996fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
9997fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      I32 in ireg, according to prevailing SSE rounding mode */
9998fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
99990b21044f0cbfd84788247ed7ba65cf77ea832a2csewardj      I32 in ireg, rounding towards zero */
10000fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F
10001fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj       && (insn[2] == 0x2D || insn[2] == 0x2C)) {
10002fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
10003fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f64lo = newTemp(Ity_F64);
100042d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool   r2zero = toBool(insn[2] == 0x2C);
10005fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
10006fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10007fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
10008fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
10009fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
10010fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
10011fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
10012fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   nameXMMReg(eregOfRM(modrm)),
10013fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   nameIReg(4, gregOfRM(modrm)));
10014fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
10015fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10016fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10017fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
10018fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
10019fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   dis_buf,
10020fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   nameIReg(4, gregOfRM(modrm)));
10021fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
10022fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10023fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (r2zero) {
10024fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( rmode, mkU32((UInt)Irrm_ZERO) );
10025fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
10026fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( rmode, get_sse_roundingmode() );
10027fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
10028fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10029fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putIReg(4, gregOfRM(modrm),
100306c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo)) );
10031fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10032fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
10033fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
10034fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10035fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
10036fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      low 1/4 xmm(G), according to prevailing SSE rounding mode */
10037fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
10038fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
10039fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f64lo = newTemp(Ity_F64);
10040fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
10041fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10042fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
10043fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
10044fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
10045fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
10046fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10047fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
10048fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
10049fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10050fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10051fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
10052fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtsd2ss %s,%s\n", dis_buf,
10053fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
10054fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
10055fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10056fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, get_sse_roundingmode() );
10057fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F(
10058fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         gregOfRM(modrm), 0,
10059fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
10060fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      );
10061fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10062fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
10063fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
10064fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10065fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
10066fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      half xmm */
10067fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
10068fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp arg32 = newTemp(Ity_I32);
10069fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
10070fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10071fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
10072fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
10073fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( arg32, getIReg(4, eregOfRM(modrm)) );
10074fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
10075fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
10076fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
10077fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
10078fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10079fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
10080fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
10081fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtsi2sd %s,%s\n", dis_buf,
10082fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
10083fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
10084fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10085fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F(
10086fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         gregOfRM(modrm), 0,
100876c299f3acab617581ea504e45fbb6cab24c2b29fsewardj         unop(Iop_I32StoF64, mkexpr(arg32)) );
10088fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10089fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
10090fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
10091fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10092fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
10093fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      low half xmm(G) */
10094fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
10095fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f32lo = newTemp(Ity_F32);
10096fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
10097fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10098fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
10099fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
10100fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
10101fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
10102fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10103fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
10104fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
10105fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10106fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
10107fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
10108fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtss2sd %s,%s\n", dis_buf,
10109fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
10110fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
10111fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10112fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F( gregOfRM(modrm), 0,
10113fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                        unop( Iop_F32toF64, mkexpr(f32lo) ) );
10114fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10115fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
10116fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
10117fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10118fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
10119fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      lo half xmm(G), and zero upper half, rounding towards zero */
10120fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
10121fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argV  = newTemp(Ity_V128);
10122fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
10123fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10124fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
10125fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
10126fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argV, getXMMReg(eregOfRM(modrm)) );
10127fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
10128fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10129fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                  nameXMMReg(gregOfRM(modrm)));
10130fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
10131fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10132fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10133fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
10134fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvttpd2dq %s,%s\n", dis_buf,
10135fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                  nameXMMReg(gregOfRM(modrm)) );
10136fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
10137fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10138fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, mkU32((UInt)Irrm_ZERO) );
10139fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10140fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      t0 = newTemp(Ity_F64);
10141fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      t1 = newTemp(Ity_F64);
10142fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( t0, unop(Iop_ReinterpI64asF64,
10143f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                       unop(Iop_V128to64, mkexpr(argV))) );
10144fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( t1, unop(Iop_ReinterpI64asF64,
10145f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                       unop(Iop_V128HIto64, mkexpr(argV))) );
10146fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
101476c299f3acab617581ea504e45fbb6cab24c2b29fsewardj#     define CVT(_t)  binop( Iop_F64toI32S,                   \
10148fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(rmode),                   \
10149fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(_t) )
10150fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10151fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
10152fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
10153fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
10154fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
10155fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10156fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     undef CVT
10157fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10158fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
10159fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
10160fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10161fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
10162fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      xmm(G), rounding towards zero */
10163fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
10164fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argV  = newTemp(Ity_V128);
10165fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
10166fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
10167fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10168fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
10169fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
10170fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argV, getXMMReg(eregOfRM(modrm)) );
10171fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
10172fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10173fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                  nameXMMReg(gregOfRM(modrm)));
10174fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
10175fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10176fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10177fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
10178fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvttps2dq %s,%s\n", dis_buf,
10179fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                  nameXMMReg(gregOfRM(modrm)) );
10180fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
10181fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10182fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, mkU32((UInt)Irrm_ZERO) );
10183fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
10184fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10185fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      /* This is less than ideal.  If it turns out to be a performance
10186fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 bottleneck it can be improved. */
10187fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     define CVT(_t)                            \
101886c299f3acab617581ea504e45fbb6cab24c2b29fsewardj        binop( Iop_F64toI32S,                   \
10189fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj               mkexpr(rmode),                   \
10190fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj               unop( Iop_F32toF64,              \
10191fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                     unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
10192fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10193fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
10194fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
10195fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
10196fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
10197fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10198fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     undef CVT
10199fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10200fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
10201fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
10202fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10203fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
10204fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
10205fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
10206fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
10207fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
10208fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10209c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
10210c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5E) {
10211c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10212c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "divsd", Iop_Div64F0x2 );
10213c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10214c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10215c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10216c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 0F AE /5 = LFENCE -- flush pending operations to memory */
10217c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 0F AE /6 = MFENCE -- flush pending operations to memory */
10218c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0x0F && insn[1] == 0xAE
10219c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj       && epartIsReg(insn[2])
10220c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj       && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
10221c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10222c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      delta += 3;
102233e83893fff6c7bbc955d4529cd922df4ed9b23cdsewardj      /* Insert a memory fence.  It's sometimes important that these
102243e83893fff6c7bbc955d4529cd922df4ed9b23cdsewardj         are carried through to the generated code. */
10225c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      stmt( IRStmt_MBE(Imbe_Fence) );
10226c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
10227c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10228c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10229c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10230c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
10231c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
10232c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
10233c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10234c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10235c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10236c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
10237c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5F) {
10238c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10239c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "maxsd", Iop_Max64F0x2 );
10240c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10241c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10242c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10243c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
10244c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
10245c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
10246c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10247c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10248c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10249c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
10250c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) {
10251c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10252c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 );
10253c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10254c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10255c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10256c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
10257c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
10258c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
10259c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F
10260c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj       && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
1026155085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* wot = insn[1]==0x28 ? "apd" :
1026255085f8680acc89d727e321f3b34cae1a8c4093aflorian                         insn[1]==0x10 ? "upd" : "dqa";
10263c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10264c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10265c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( gregOfRM(modrm),
10266c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    getXMMReg( eregOfRM(modrm) ));
10267c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)),
10268c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                   nameXMMReg(gregOfRM(modrm)));
10269c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+1;
10270c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10271c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
1027245ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj         if (insn[1] == 0x28/*movapd*/ || insn[1] == 0x6F/*movdqa*/)
1027345ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj            gen_SEGV_if_not_16_aligned( addr );
10274c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( gregOfRM(modrm),
10275c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    loadLE(Ity_V128, mkexpr(addr)) );
10276c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("mov%s %s,%s\n", wot, dis_buf,
10277c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                   nameXMMReg(gregOfRM(modrm)));
10278c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10279c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10280c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10281c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10282c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
1028395535feeb27c5641608bc9eb83c047837281a7f4sewardj   /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
102841c31877a29646fb6f902de217ae8f62bccfeda7dsewardj   /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
102851c31877a29646fb6f902de217ae8f62bccfeda7dsewardj   if (sz == 2 && insn[0] == 0x0F
102861c31877a29646fb6f902de217ae8f62bccfeda7dsewardj       && (insn[1] == 0x29 || insn[1] == 0x11)) {
1028755085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* wot = insn[1]==0x29 ? "apd" : "upd";
1028895535feeb27c5641608bc9eb83c047837281a7f4sewardj      modrm = getIByte(delta+2);
1028995535feeb27c5641608bc9eb83c047837281a7f4sewardj      if (epartIsReg(modrm)) {
1029095535feeb27c5641608bc9eb83c047837281a7f4sewardj         /* fall through; awaiting test case */
1029195535feeb27c5641608bc9eb83c047837281a7f4sewardj      } else {
1029295535feeb27c5641608bc9eb83c047837281a7f4sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
1029345ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj         if (insn[1] == 0x29/*movapd*/)
1029445ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj            gen_SEGV_if_not_16_aligned( addr );
1029595535feeb27c5641608bc9eb83c047837281a7f4sewardj         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
102961c31877a29646fb6f902de217ae8f62bccfeda7dsewardj         DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRM(modrm)),
102971c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                                   dis_buf );
1029895535feeb27c5641608bc9eb83c047837281a7f4sewardj         delta += 2+alen;
1029995535feeb27c5641608bc9eb83c047837281a7f4sewardj         goto decode_success;
1030095535feeb27c5641608bc9eb83c047837281a7f4sewardj      }
1030195535feeb27c5641608bc9eb83c047837281a7f4sewardj   }
1030295535feeb27c5641608bc9eb83c047837281a7f4sewardj
10303c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
10304c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
10305c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10306c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10307c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+1;
10308c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg(
10309c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj            gregOfRM(modrm),
10310f0c1c58d6e47608ce166058997f795f1d7d45127sewardj            unop( Iop_32UtoV128, getIReg(4, eregOfRM(modrm)) )
10311c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         );
10312c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movd %s, %s\n",
10313c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj             nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
10314c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10315c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode( &alen, sorb, delta+2, dis_buf );
10316c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10317c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg(
10318c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj            gregOfRM(modrm),
10319f0c1c58d6e47608ce166058997f795f1d7d45127sewardj            unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
10320c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         );
10321c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
10322c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10323c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10324c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10325c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10326c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
10327c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
10328c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10329c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10330c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+1;
10331c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putIReg( 4, eregOfRM(modrm),
10332c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                  getXMMRegLane32(gregOfRM(modrm), 0) );
10333c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movd %s, %s\n",
10334c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj             nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
10335c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10336c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode( &alen, sorb, delta+2, dis_buf );
10337c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10338c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr),
10339c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                  getXMMRegLane32(gregOfRM(modrm), 0) );
10340c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10341c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10342c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10343c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10344c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10345c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
10346c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
10347c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10348c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10349c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+1;
10350c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( eregOfRM(modrm),
10351c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    getXMMReg(gregOfRM(modrm)) );
10352c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10353c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                nameXMMReg(eregOfRM(modrm)));
10354c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10355c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode( &alen, sorb, delta+2, dis_buf );
10356c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
1035745ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj         gen_SEGV_if_not_16_aligned( addr );
10358c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10359c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10360c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10361c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10362c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10363c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10364c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
10365c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* Unfortunately can't simply use the MOVDQA case since the
10366c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      prefix lengths are different (66 vs F3) */
10367c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
10368c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10369c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+3);
10370c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10371c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( gregOfRM(modrm),
10372c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    getXMMReg( eregOfRM(modrm) ));
10373c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10374c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                               nameXMMReg(gregOfRM(modrm)));
10375c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+1;
10376c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10377c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10378c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( gregOfRM(modrm),
10379c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    loadLE(Ity_V128, mkexpr(addr)) );
10380c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdqu %s,%s\n", dis_buf,
10381c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                               nameXMMReg(gregOfRM(modrm)));
10382c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+alen;
10383c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10384c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10385c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10386c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10387c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
10388c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* Unfortunately can't simply use the MOVDQA case since the
10389c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      prefix lengths are different (66 vs F3) */
10390c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
10391c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10392c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+3);
10393c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10394c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+1;
10395c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( eregOfRM(modrm),
10396c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    getXMMReg(gregOfRM(modrm)) );
10397c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10398c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                nameXMMReg(eregOfRM(modrm)));
10399c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10400c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode( &alen, sorb, delta+3, dis_buf );
10401c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+alen;
10402c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10403c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10404c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10405c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10406c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10407c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10408c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
10409c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
10410c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10411c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+3);
10412c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10413c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         do_MMX_preamble();
10414c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putMMXReg( gregOfRM(modrm),
10415c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    getXMMRegLane64( eregOfRM(modrm), 0 ));
10416c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10417c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                nameMMXReg(gregOfRM(modrm)));
10418c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+1;
10419c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10420c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10421c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         /* fall through, apparently no mem case for this insn */
10422c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10423c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10424c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10425c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
10426c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* These seems identical to MOVHPS.  This instruction encoding is
10427c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      completely crazy. */
10428c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
10429c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10430c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10431c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         /* fall through; apparently reg-reg is not possible */
10432c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10433c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10434c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10435c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
10436c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                          loadLE(Ity_I64, mkexpr(addr)) );
10437c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movhpd %s,%s\n", dis_buf,
10438c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                               nameXMMReg( gregOfRM(modrm) ));
10439c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10440c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10441c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10442c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10443c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
10444c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* Again, this seems identical to MOVHPS. */
10445c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
10446c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (!epartIsReg(insn[2])) {
10447c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2;
10448c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta, dis_buf );
10449c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += alen;
10450c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr),
10451c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                  getXMMRegLane64( gregOfRM(insn[2]),
10452c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                   1/*upper lane*/ ) );
10453c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
10454c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                               dis_buf);
10455c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10456c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10457c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      /* else fall through */
10458c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10459c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10460c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
10461c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* Identical to MOVLPS ? */
10462c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x12) {
10463c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10464c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10465c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         /* fall through; apparently reg-reg is not possible */
10466c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10467c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10468c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10469c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMRegLane64( gregOfRM(modrm),  0/*lower lane*/,
10470c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                          loadLE(Ity_I64, mkexpr(addr)) );
10471c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movlpd %s, %s\n",
10472c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj             dis_buf, nameXMMReg( gregOfRM(modrm) ));
10473c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10474c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10475c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10476c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10477c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
10478c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* Identical to MOVLPS ? */
10479c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
10480c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (!epartIsReg(insn[2])) {
10481c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2;
10482c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta, dis_buf );
10483c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += alen;
10484c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr),
10485c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                  getXMMRegLane64( gregOfRM(insn[2]),
10486c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                   0/*lower lane*/ ) );
10487c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
10488c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                dis_buf);
10489c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10490c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10491c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      /* else fall through */
10492c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10493c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10494c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10495c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      2 lowest bits of ireg(G) */
10496c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0x0F && insn[1] == 0x50) {
10497c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10498c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (sz == 2 && epartIsReg(modrm)) {
10499c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         Int src;
10500c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         t0 = newTemp(Ity_I32);
10501c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         t1 = newTemp(Ity_I32);
10502c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+1;
10503c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         src = eregOfRM(modrm);
10504c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         assign( t0, binop( Iop_And32,
10505c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                            binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10506c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                            mkU32(1) ));
10507c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         assign( t1, binop( Iop_And32,
10508c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                            binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10509c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                            mkU32(2) ));
10510c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putIReg(4, gregOfRM(modrm),
10511c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10512c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                 );
10513c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movmskpd %s,%s\n", nameXMMReg(src),
10514c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                 nameIReg(4, gregOfRM(modrm)));
10515c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10516c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10517c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      /* else fall through */
10518c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10519c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10520d71ba837242cc470f622335b1c650bce8886a533sewardj   /* 66 0F F7 = MASKMOVDQU -- store selected bytes of double quadword */
10521d71ba837242cc470f622335b1c650bce8886a533sewardj   if (insn[0] == 0x0F && insn[1] == 0xF7) {
10522d71ba837242cc470f622335b1c650bce8886a533sewardj      modrm = getIByte(delta+2);
10523d71ba837242cc470f622335b1c650bce8886a533sewardj      if (sz == 2 && epartIsReg(modrm)) {
10524d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp regD    = newTemp(Ity_V128);
10525d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp mask    = newTemp(Ity_V128);
10526d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp olddata = newTemp(Ity_V128);
10527d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp newdata = newTemp(Ity_V128);
10528d71ba837242cc470f622335b1c650bce8886a533sewardj                addr    = newTemp(Ity_I32);
10529d71ba837242cc470f622335b1c650bce8886a533sewardj
10530d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
10531d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( regD, getXMMReg( gregOfRM(modrm) ));
10532d71ba837242cc470f622335b1c650bce8886a533sewardj
10533d71ba837242cc470f622335b1c650bce8886a533sewardj         /* Unfortunately can't do the obvious thing with SarN8x16
10534d71ba837242cc470f622335b1c650bce8886a533sewardj            here since that can't be re-emitted as SSE2 code - no such
10535d71ba837242cc470f622335b1c650bce8886a533sewardj            insn. */
10536d71ba837242cc470f622335b1c650bce8886a533sewardj	 assign(
10537d71ba837242cc470f622335b1c650bce8886a533sewardj            mask,
10538d71ba837242cc470f622335b1c650bce8886a533sewardj            binop(Iop_64HLtoV128,
10539d71ba837242cc470f622335b1c650bce8886a533sewardj                  binop(Iop_SarN8x8,
10540d71ba837242cc470f622335b1c650bce8886a533sewardj                        getXMMRegLane64( eregOfRM(modrm), 1 ),
10541d71ba837242cc470f622335b1c650bce8886a533sewardj                        mkU8(7) ),
10542d71ba837242cc470f622335b1c650bce8886a533sewardj                  binop(Iop_SarN8x8,
10543d71ba837242cc470f622335b1c650bce8886a533sewardj                        getXMMRegLane64( eregOfRM(modrm), 0 ),
10544d71ba837242cc470f622335b1c650bce8886a533sewardj                        mkU8(7) ) ));
10545d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( olddata, loadLE( Ity_V128, mkexpr(addr) ));
10546d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( newdata,
10547d71ba837242cc470f622335b1c650bce8886a533sewardj                 binop(Iop_OrV128,
10548d71ba837242cc470f622335b1c650bce8886a533sewardj                       binop(Iop_AndV128,
10549d71ba837242cc470f622335b1c650bce8886a533sewardj                             mkexpr(regD),
10550d71ba837242cc470f622335b1c650bce8886a533sewardj                             mkexpr(mask) ),
10551d71ba837242cc470f622335b1c650bce8886a533sewardj                       binop(Iop_AndV128,
10552d71ba837242cc470f622335b1c650bce8886a533sewardj                             mkexpr(olddata),
10553d71ba837242cc470f622335b1c650bce8886a533sewardj                             unop(Iop_NotV128, mkexpr(mask)))) );
10554d71ba837242cc470f622335b1c650bce8886a533sewardj         storeLE( mkexpr(addr), mkexpr(newdata) );
10555d71ba837242cc470f622335b1c650bce8886a533sewardj
10556d71ba837242cc470f622335b1c650bce8886a533sewardj         delta += 2+1;
10557d71ba837242cc470f622335b1c650bce8886a533sewardj         DIP("maskmovdqu %s,%s\n", nameXMMReg( eregOfRM(modrm) ),
10558d71ba837242cc470f622335b1c650bce8886a533sewardj                                   nameXMMReg( gregOfRM(modrm) ) );
10559d71ba837242cc470f622335b1c650bce8886a533sewardj         goto decode_success;
10560d71ba837242cc470f622335b1c650bce8886a533sewardj      }
10561d71ba837242cc470f622335b1c650bce8886a533sewardj      /* else fall through */
10562d71ba837242cc470f622335b1c650bce8886a533sewardj   }
10563d71ba837242cc470f622335b1c650bce8886a533sewardj
10564c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10565c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0x0F && insn[1] == 0xE7) {
10566c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10567c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (sz == 2 && !epartIsReg(modrm)) {
10568c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
1056945ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj         gen_SEGV_if_not_16_aligned( addr );
10570c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10571c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movntdq %s,%s\n", dis_buf,
10572c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                nameXMMReg(gregOfRM(modrm)));
10573c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10574c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10575c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10576c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      /* else fall through */
10577c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10578c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10579c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10580c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0x0F && insn[1] == 0xC3) {
10581c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10582c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10583c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (!epartIsReg(modrm)) {
10584c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10585c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
10586c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movnti %s,%s\n", dis_buf,
10587c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                               nameIReg(4, gregOfRM(modrm)));
10588c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10589c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10590c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10591c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      /* else fall through */
10592c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10593c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
1059495535feeb27c5641608bc9eb83c047837281a7f4sewardj   /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
1059595535feeb27c5641608bc9eb83c047837281a7f4sewardj      or lo half xmm).  */
105969ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
105979ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      modrm = getIByte(delta+2);
105989ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      if (epartIsReg(modrm)) {
105999ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj         /* fall through, awaiting test case */
106006d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj         /* dst: lo half copied, hi half zeroed */
106019ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      } else {
106029ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
106039ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj         storeLE( mkexpr(addr),
106049ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj                  getXMMRegLane64( gregOfRM(modrm), 0 ));
106059ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj         DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
106069ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj         delta += 2+alen;
106079ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj         goto decode_success;
106089ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      }
106099ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj   }
106109ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj
10611c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10612c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      hi half). */
10613c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
10614c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10615c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+3);
10616c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10617c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         do_MMX_preamble();
10618c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( gregOfRM(modrm),
10619f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                    unop(Iop_64UtoV128, getMMXReg( eregOfRM(modrm) )) );
10620c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10621c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                nameXMMReg(gregOfRM(modrm)));
10622c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+1;
10623c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10624c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10625c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         /* fall through, apparently no mem case for this insn */
10626c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10627c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10628c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
1062995535feeb27c5641608bc9eb83c047837281a7f4sewardj   /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
106306d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj      G (lo half xmm).  Upper half of G is zeroed out. */
1063195535feeb27c5641608bc9eb83c047837281a7f4sewardj   /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
1063295535feeb27c5641608bc9eb83c047837281a7f4sewardj      G (lo half xmm).  If E is mem, upper half of G is zeroed out.
106336d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj      If E is reg, upper half of G is unchanged. */
1063495535feeb27c5641608bc9eb83c047837281a7f4sewardj   if ((insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x10)
1063595535feeb27c5641608bc9eb83c047837281a7f4sewardj       || (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7E)) {
10636c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10637c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+3);
10638c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10639c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMRegLane64( gregOfRM(modrm), 0,
10640c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                          getXMMRegLane64( eregOfRM(modrm), 0 ));
106416d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj         if (insn[0] == 0xF3/*MOVQ*/) {
106426d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj            /* zero bits 127:64 */
106436d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj            putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
106446d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj         }
10645c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movsd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10646c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                              nameXMMReg(gregOfRM(modrm)));
10647c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+1;
10648c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10649c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10650ad50db03b717271467900b0616bc9e6c492f063dsewardj         /* zero bits 127:64 */
106515bf1fd45a1db0c7f2f51af6e1be3849b01a40e9esewardj         putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
10652ad50db03b717271467900b0616bc9e6c492f063dsewardj         /* write bits 63:0 */
10653c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMRegLane64( gregOfRM(modrm), 0,
10654c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                          loadLE(Ity_I64, mkexpr(addr)) );
10655c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movsd %s,%s\n", dis_buf,
10656c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                              nameXMMReg(gregOfRM(modrm)));
10657c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+alen;
10658c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10659c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10660c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10661c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10662c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10663c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      or lo half xmm). */
10664c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x11) {
10665c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10666c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+3);
10667c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10668b7ba04ff6522c540cea057c4124e675b5f64ec46sewardj         putXMMRegLane64( eregOfRM(modrm), 0,
10669b7ba04ff6522c540cea057c4124e675b5f64ec46sewardj                          getXMMRegLane64( gregOfRM(modrm), 0 ));
10670b7ba04ff6522c540cea057c4124e675b5f64ec46sewardj         DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
10671b7ba04ff6522c540cea057c4124e675b5f64ec46sewardj                              nameXMMReg(eregOfRM(modrm)));
10672b7ba04ff6522c540cea057c4124e675b5f64ec46sewardj         delta += 3+1;
10673c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10674c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10675c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr),
10676519d66fc0e4f16b120079bc651862e49f154da62sewardj                  getXMMRegLane64(gregOfRM(modrm), 0) );
10677519d66fc0e4f16b120079bc651862e49f154da62sewardj         DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
10678c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                              dis_buf);
10679c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+alen;
10680c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10681b7ba04ff6522c540cea057c4124e675b5f64ec46sewardj      goto decode_success;
10682c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10683fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10684008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10685008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
10686008754b1685e50d117f9c982ddeeafbaca151bfesewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
10687008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10688008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10689008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10690008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
10691008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
10692008754b1685e50d117f9c982ddeeafbaca151bfesewardj      vassert(sz == 4);
10693008754b1685e50d117f9c982ddeeafbaca151bfesewardj      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
10694008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10695008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10696008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10697008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 56 = ORPD -- G = G and E */
10698008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
10699f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_OrV128 );
10700008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10701008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10702008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10703008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10704008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
10705008754b1685e50d117f9c982ddeeafbaca151bfesewardj      Int    select;
10706008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp sV = newTemp(Ity_V128);
10707008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp dV = newTemp(Ity_V128);
10708008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp s1 = newTemp(Ity_I64);
10709008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp s0 = newTemp(Ity_I64);
10710008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp d1 = newTemp(Ity_I64);
10711008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp d0 = newTemp(Ity_I64);
10712008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10713008754b1685e50d117f9c982ddeeafbaca151bfesewardj      modrm = insn[2];
10714008754b1685e50d117f9c982ddeeafbaca151bfesewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
10715008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10716008754b1685e50d117f9c982ddeeafbaca151bfesewardj      if (epartIsReg(modrm)) {
10717008754b1685e50d117f9c982ddeeafbaca151bfesewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
10718008754b1685e50d117f9c982ddeeafbaca151bfesewardj         select = (Int)insn[3];
10719008754b1685e50d117f9c982ddeeafbaca151bfesewardj         delta += 2+2;
10720008754b1685e50d117f9c982ddeeafbaca151bfesewardj         DIP("shufpd $%d,%s,%s\n", select,
10721008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                   nameXMMReg(eregOfRM(modrm)),
10722008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                   nameXMMReg(gregOfRM(modrm)));
10723008754b1685e50d117f9c982ddeeafbaca151bfesewardj      } else {
10724008754b1685e50d117f9c982ddeeafbaca151bfesewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10725008754b1685e50d117f9c982ddeeafbaca151bfesewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10726008754b1685e50d117f9c982ddeeafbaca151bfesewardj         select = (Int)insn[2+alen];
10727008754b1685e50d117f9c982ddeeafbaca151bfesewardj         delta += 3+alen;
10728008754b1685e50d117f9c982ddeeafbaca151bfesewardj         DIP("shufpd $%d,%s,%s\n", select,
10729008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                   dis_buf,
10730008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                   nameXMMReg(gregOfRM(modrm)));
10731008754b1685e50d117f9c982ddeeafbaca151bfesewardj      }
10732008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10733f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10734f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( d0, unop(Iop_V128to64,   mkexpr(dV)) );
10735f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10736f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( s0, unop(Iop_V128to64,   mkexpr(sV)) );
10737008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10738008754b1685e50d117f9c982ddeeafbaca151bfesewardj#     define SELD(n) mkexpr((n)==0 ? d0 : d1)
10739008754b1685e50d117f9c982ddeeafbaca151bfesewardj#     define SELS(n) mkexpr((n)==0 ? s0 : s1)
10740008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10741008754b1685e50d117f9c982ddeeafbaca151bfesewardj      putXMMReg(
10742008754b1685e50d117f9c982ddeeafbaca151bfesewardj         gregOfRM(modrm),
10743f0c1c58d6e47608ce166058997f795f1d7d45127sewardj         binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
10744008754b1685e50d117f9c982ddeeafbaca151bfesewardj      );
10745008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10746008754b1685e50d117f9c982ddeeafbaca151bfesewardj#     undef SELD
10747008754b1685e50d117f9c982ddeeafbaca151bfesewardj#     undef SELS
10748008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10749008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10750008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10751008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10752008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10753008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
10754008754b1685e50d117f9c982ddeeafbaca151bfesewardj      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
10755008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                        "sqrtpd", Iop_Sqrt64Fx2 );
10756008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10757008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10758008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10759008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10760008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
10761008754b1685e50d117f9c982ddeeafbaca151bfesewardj      vassert(sz == 4);
10762008754b1685e50d117f9c982ddeeafbaca151bfesewardj      delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3,
10763008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                         "sqrtsd", Iop_Sqrt64F0x2 );
10764008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10765008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10766008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10767008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10768008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
10769008754b1685e50d117f9c982ddeeafbaca151bfesewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
10770008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10771008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10772008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10773008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10774008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
10775008754b1685e50d117f9c982ddeeafbaca151bfesewardj      vassert(sz == 4);
10776008754b1685e50d117f9c982ddeeafbaca151bfesewardj      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
10777008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10778008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10779008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10780008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10781008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10782008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* These just appear to be special cases of SHUFPS */
10783008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10784008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp s1 = newTemp(Ity_I64);
10785008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp s0 = newTemp(Ity_I64);
10786008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp d1 = newTemp(Ity_I64);
10787008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp d0 = newTemp(Ity_I64);
10788008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp sV = newTemp(Ity_V128);
10789008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp dV = newTemp(Ity_V128);
107902d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool   hi = toBool(insn[1] == 0x15);
10791008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10792008754b1685e50d117f9c982ddeeafbaca151bfesewardj      modrm = insn[2];
10793008754b1685e50d117f9c982ddeeafbaca151bfesewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
10794008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10795008754b1685e50d117f9c982ddeeafbaca151bfesewardj      if (epartIsReg(modrm)) {
10796008754b1685e50d117f9c982ddeeafbaca151bfesewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
10797008754b1685e50d117f9c982ddeeafbaca151bfesewardj         delta += 2+1;
10798008754b1685e50d117f9c982ddeeafbaca151bfesewardj         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10799008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                  nameXMMReg(eregOfRM(modrm)),
10800008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                  nameXMMReg(gregOfRM(modrm)));
10801008754b1685e50d117f9c982ddeeafbaca151bfesewardj      } else {
10802008754b1685e50d117f9c982ddeeafbaca151bfesewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10803008754b1685e50d117f9c982ddeeafbaca151bfesewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10804008754b1685e50d117f9c982ddeeafbaca151bfesewardj         delta += 2+alen;
10805008754b1685e50d117f9c982ddeeafbaca151bfesewardj         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10806008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                  dis_buf,
10807008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                  nameXMMReg(gregOfRM(modrm)));
10808008754b1685e50d117f9c982ddeeafbaca151bfesewardj      }
10809008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10810f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10811f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( d0, unop(Iop_V128to64,   mkexpr(dV)) );
10812f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10813f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( s0, unop(Iop_V128to64,   mkexpr(sV)) );
10814008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10815008754b1685e50d117f9c982ddeeafbaca151bfesewardj      if (hi) {
10816008754b1685e50d117f9c982ddeeafbaca151bfesewardj         putXMMReg( gregOfRM(modrm),
10817f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                    binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
10818008754b1685e50d117f9c982ddeeafbaca151bfesewardj      } else {
10819008754b1685e50d117f9c982ddeeafbaca151bfesewardj         putXMMReg( gregOfRM(modrm),
10820f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                    binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
10821008754b1685e50d117f9c982ddeeafbaca151bfesewardj      }
10822008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10823008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10824008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10825008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10826008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 57 = XORPD -- G = G and E */
10827008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
10828f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_XorV128 );
10829008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10830008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10831636ad762e49597ef608323f27c7b8eb66962cd90sewardj
10832164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F 6B = PACKSSDW */
10833164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
10834164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10835c9bff7dbb37ba2ee5898ef49aefaa92095ab446bsewardj                                 "packssdw",
108365f438dd73072211989c6d496845bdc9b777ecbecsewardj                                 Iop_QNarrowBin32Sto16Sx8, True );
10837164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10838164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10839164f9275c465cd09ecd09276b8542282f5def250sewardj
10840164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F 63 = PACKSSWB */
10841164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
10842164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10843c9bff7dbb37ba2ee5898ef49aefaa92095ab446bsewardj                                 "packsswb",
108445f438dd73072211989c6d496845bdc9b777ecbecsewardj                                 Iop_QNarrowBin16Sto8Sx16, True );
10845164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10846164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10847164f9275c465cd09ecd09276b8542282f5def250sewardj
10848164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F 67 = PACKUSWB */
10849164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
10850164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10851c9bff7dbb37ba2ee5898ef49aefaa92095ab446bsewardj                                 "packuswb",
108525f438dd73072211989c6d496845bdc9b777ecbecsewardj                                 Iop_QNarrowBin16Sto8Ux16, True );
10853164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10854164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10855164f9275c465cd09ecd09276b8542282f5def250sewardj
10856164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F FC = PADDB */
10857164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
10858164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10859164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddb", Iop_Add8x16, False );
10860164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10861164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10862164f9275c465cd09ecd09276b8542282f5def250sewardj
10863164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F FE = PADDD */
10864164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
10865164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10866164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddd", Iop_Add32x4, False );
10867164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10868164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10869164f9275c465cd09ecd09276b8542282f5def250sewardj
10870164f9275c465cd09ecd09276b8542282f5def250sewardj   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10871164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 0F D4 = PADDQ -- add 64x1 */
10872164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
10873164f9275c465cd09ecd09276b8542282f5def250sewardj      do_MMX_preamble();
10874164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_MMXop_regmem_to_reg (
10875164f9275c465cd09ecd09276b8542282f5def250sewardj                sorb, delta+2, insn[1], "paddq", False );
10876164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10877164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10878164f9275c465cd09ecd09276b8542282f5def250sewardj
10879164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F D4 = PADDQ */
10880164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
10881164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10882164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddq", Iop_Add64x2, False );
10883164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10884164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10885164f9275c465cd09ecd09276b8542282f5def250sewardj
10886164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F FD = PADDW */
10887164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
10888164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10889164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddw", Iop_Add16x8, False );
10890164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10891164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10892164f9275c465cd09ecd09276b8542282f5def250sewardj
10893164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F EC = PADDSB */
10894164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
10895164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10896164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddsb", Iop_QAdd8Sx16, False );
10897164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10898164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10899164f9275c465cd09ecd09276b8542282f5def250sewardj
10900164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F ED = PADDSW */
10901164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
10902164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10903164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddsw", Iop_QAdd16Sx8, False );
10904164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10905164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10906164f9275c465cd09ecd09276b8542282f5def250sewardj
10907164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F DC = PADDUSB */
10908164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
10909164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10910164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddusb", Iop_QAdd8Ux16, False );
10911164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10912164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10913164f9275c465cd09ecd09276b8542282f5def250sewardj
10914164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F DD = PADDUSW */
10915164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
10916164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10917164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddusw", Iop_QAdd16Ux8, False );
10918164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10919164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10920164f9275c465cd09ecd09276b8542282f5def250sewardj
10921164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F DB = PAND */
10922164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
10923f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_AndV128 );
10924164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10925164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10926164f9275c465cd09ecd09276b8542282f5def250sewardj
10927164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F DF = PANDN */
10928164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
10929f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_AndV128 );
10930164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10931164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10932164f9275c465cd09ecd09276b8542282f5def250sewardj
10933164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F E0 = PAVGB */
10934164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
10935164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10936164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "pavgb", Iop_Avg8Ux16, False );
10937164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10938164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10939164f9275c465cd09ecd09276b8542282f5def250sewardj
10940164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F E3 = PAVGW */
10941164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
10942164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10943164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "pavgw", Iop_Avg16Ux8, False );
10944164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10945164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10946164f9275c465cd09ecd09276b8542282f5def250sewardj
10947e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F 74 = PCMPEQB */
10948e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
10949e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10950e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pcmpeqb", Iop_CmpEQ8x16, False );
10951e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
10952e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10953e5854d6d470f21677ec84f71d09129434b044246sewardj
10954e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F 76 = PCMPEQD */
10955e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
10956e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10957e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pcmpeqd", Iop_CmpEQ32x4, False );
10958e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
10959e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10960e5854d6d470f21677ec84f71d09129434b044246sewardj
10961e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F 75 = PCMPEQW */
10962e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
10963e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10964e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pcmpeqw", Iop_CmpEQ16x8, False );
10965e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
10966e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10967e5854d6d470f21677ec84f71d09129434b044246sewardj
10968e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F 64 = PCMPGTB */
10969e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
10970e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10971e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pcmpgtb", Iop_CmpGT8Sx16, False );
10972e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
10973e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10974e5854d6d470f21677ec84f71d09129434b044246sewardj
10975e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F 66 = PCMPGTD */
10976e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
10977e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10978e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pcmpgtd", Iop_CmpGT32Sx4, False );
10979e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
10980e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10981e5854d6d470f21677ec84f71d09129434b044246sewardj
10982e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F 65 = PCMPGTW */
10983e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
10984e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10985e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pcmpgtw", Iop_CmpGT16Sx8, False );
10986e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
10987e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10988e5854d6d470f21677ec84f71d09129434b044246sewardj
10989e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10990e5854d6d470f21677ec84f71d09129434b044246sewardj      zero-extend of it in ireg(G). */
10991e5854d6d470f21677ec84f71d09129434b044246sewardj   if (insn[0] == 0x0F && insn[1] == 0xC5) {
10992e5854d6d470f21677ec84f71d09129434b044246sewardj      modrm = insn[2];
10993e5854d6d470f21677ec84f71d09129434b044246sewardj      if (sz == 2 && epartIsReg(modrm)) {
10994e5854d6d470f21677ec84f71d09129434b044246sewardj         t5 = newTemp(Ity_V128);
10995e5854d6d470f21677ec84f71d09129434b044246sewardj         t4 = newTemp(Ity_I16);
10996e5854d6d470f21677ec84f71d09129434b044246sewardj         assign(t5, getXMMReg(eregOfRM(modrm)));
10997e5854d6d470f21677ec84f71d09129434b044246sewardj         breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10998e5854d6d470f21677ec84f71d09129434b044246sewardj         switch (insn[3] & 7) {
10999e5854d6d470f21677ec84f71d09129434b044246sewardj            case 0:  assign(t4, unop(Iop_32to16,   mkexpr(t0))); break;
11000e5854d6d470f21677ec84f71d09129434b044246sewardj            case 1:  assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
11001e5854d6d470f21677ec84f71d09129434b044246sewardj            case 2:  assign(t4, unop(Iop_32to16,   mkexpr(t1))); break;
11002e5854d6d470f21677ec84f71d09129434b044246sewardj            case 3:  assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
11003e5854d6d470f21677ec84f71d09129434b044246sewardj            case 4:  assign(t4, unop(Iop_32to16,   mkexpr(t2))); break;
11004e5854d6d470f21677ec84f71d09129434b044246sewardj            case 5:  assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
11005e5854d6d470f21677ec84f71d09129434b044246sewardj            case 6:  assign(t4, unop(Iop_32to16,   mkexpr(t3))); break;
11006e5854d6d470f21677ec84f71d09129434b044246sewardj            case 7:  assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
11007ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj            default: vassert(0); /*NOTREACHED*/
11008e5854d6d470f21677ec84f71d09129434b044246sewardj         }
11009e5854d6d470f21677ec84f71d09129434b044246sewardj         putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
11010e5854d6d470f21677ec84f71d09129434b044246sewardj         DIP("pextrw $%d,%s,%s\n",
11011e5854d6d470f21677ec84f71d09129434b044246sewardj             (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
11012e5854d6d470f21677ec84f71d09129434b044246sewardj                           nameIReg(4,gregOfRM(modrm)));
11013e5854d6d470f21677ec84f71d09129434b044246sewardj         delta += 4;
11014e5854d6d470f21677ec84f71d09129434b044246sewardj         goto decode_success;
11015e5854d6d470f21677ec84f71d09129434b044246sewardj      }
11016e5854d6d470f21677ec84f71d09129434b044246sewardj      /* else fall through */
11017e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11018e5854d6d470f21677ec84f71d09129434b044246sewardj
11019e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
11020e5854d6d470f21677ec84f71d09129434b044246sewardj      put it into the specified lane of xmm(G). */
11021e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
11022e5854d6d470f21677ec84f71d09129434b044246sewardj      Int lane;
11023e5854d6d470f21677ec84f71d09129434b044246sewardj      t4 = newTemp(Ity_I16);
11024e5854d6d470f21677ec84f71d09129434b044246sewardj      modrm = insn[2];
11025e5854d6d470f21677ec84f71d09129434b044246sewardj
11026e5854d6d470f21677ec84f71d09129434b044246sewardj      if (epartIsReg(modrm)) {
11027e5854d6d470f21677ec84f71d09129434b044246sewardj         assign(t4, getIReg(2, eregOfRM(modrm)));
11028aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj         delta += 3+1;
11029aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj         lane = insn[3+1-1];
11030b173774421d015736c2316b5e6e998e7de545a5cflorian         DIP("pinsrw $%d,%s,%s\n", lane,
11031e5854d6d470f21677ec84f71d09129434b044246sewardj                                   nameIReg(2,eregOfRM(modrm)),
11032e5854d6d470f21677ec84f71d09129434b044246sewardj                                   nameXMMReg(gregOfRM(modrm)));
11033e5854d6d470f21677ec84f71d09129434b044246sewardj      } else {
11034aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11035aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj         delta += 3+alen;
11036aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj         lane = insn[3+alen-1];
11037aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj         assign(t4, loadLE(Ity_I16, mkexpr(addr)));
11038b173774421d015736c2316b5e6e998e7de545a5cflorian         DIP("pinsrw $%d,%s,%s\n", lane,
11039aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj                                   dis_buf,
11040aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj                                   nameXMMReg(gregOfRM(modrm)));
11041e5854d6d470f21677ec84f71d09129434b044246sewardj      }
11042e5854d6d470f21677ec84f71d09129434b044246sewardj
11043e5854d6d470f21677ec84f71d09129434b044246sewardj      putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
11044e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11045e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11046e5854d6d470f21677ec84f71d09129434b044246sewardj
11047b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj   /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
11048b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      E(xmm or mem) to G(xmm) */
11049b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF5) {
11050b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp s1V  = newTemp(Ity_V128);
11051b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp s2V  = newTemp(Ity_V128);
11052b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp dV   = newTemp(Ity_V128);
11053b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp s1Hi = newTemp(Ity_I64);
11054b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp s1Lo = newTemp(Ity_I64);
11055b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp s2Hi = newTemp(Ity_I64);
11056b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp s2Lo = newTemp(Ity_I64);
11057b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp dHi  = newTemp(Ity_I64);
11058b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp dLo  = newTemp(Ity_I64);
11059b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      modrm = insn[2];
11060b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      if (epartIsReg(modrm)) {
11061b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         assign( s1V, getXMMReg(eregOfRM(modrm)) );
11062b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         delta += 2+1;
11063b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11064b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                                nameXMMReg(gregOfRM(modrm)));
11065b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      } else {
11066b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11067b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11068b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         delta += 2+alen;
11069b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         DIP("pmaddwd %s,%s\n", dis_buf,
11070b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                                nameXMMReg(gregOfRM(modrm)));
11071b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      }
11072b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( s2V, getXMMReg(gregOfRM(modrm)) );
11073b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11074b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( s1Lo, unop(Iop_V128to64,   mkexpr(s1V)) );
11075b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11076b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( s2Lo, unop(Iop_V128to64,   mkexpr(s2V)) );
11077b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( dHi, mkIRExprCCall(
11078b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      Ity_I64, 0/*regparms*/,
11079b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      "x86g_calculate_mmx_pmaddwd",
11080b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      &x86g_calculate_mmx_pmaddwd,
11081b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11082b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                   ));
11083b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( dLo, mkIRExprCCall(
11084b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      Ity_I64, 0/*regparms*/,
11085b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      "x86g_calculate_mmx_pmaddwd",
11086b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      &x86g_calculate_mmx_pmaddwd,
11087b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11088b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                   ));
11089b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11090b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11091b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      goto decode_success;
11092b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj   }
11093b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj
11094e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F EE = PMAXSW -- 16x8 signed max */
11095e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
11096e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11097e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pmaxsw", Iop_Max16Sx8, False );
11098e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11099e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11100e5854d6d470f21677ec84f71d09129434b044246sewardj
11101e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
11102e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
11103e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11104e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pmaxub", Iop_Max8Ux16, False );
11105e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11106e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11107e5854d6d470f21677ec84f71d09129434b044246sewardj
11108e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F EA = PMINSW -- 16x8 signed min */
11109e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
11110e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11111e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pminsw", Iop_Min16Sx8, False );
11112e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11113e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11114e5854d6d470f21677ec84f71d09129434b044246sewardj
11115e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F DA = PMINUB -- 8x16 unsigned min */
11116e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
11117e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11118e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pminub", Iop_Min8Ux16, False );
11119e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11120e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11121e5854d6d470f21677ec84f71d09129434b044246sewardj
11122e13074c2c1321d069fb95806bdce64f9a3512341sewardj   /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes
11123e13074c2c1321d069fb95806bdce64f9a3512341sewardj      in xmm(E), turn them into a byte, and put zero-extend of it in
11124e13074c2c1321d069fb95806bdce64f9a3512341sewardj      ireg(G). */
11125e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
11126e5854d6d470f21677ec84f71d09129434b044246sewardj      modrm = insn[2];
11127e5854d6d470f21677ec84f71d09129434b044246sewardj      if (epartIsReg(modrm)) {
11128e5854d6d470f21677ec84f71d09129434b044246sewardj         t0 = newTemp(Ity_I64);
11129e5854d6d470f21677ec84f71d09129434b044246sewardj         t1 = newTemp(Ity_I64);
11130e5854d6d470f21677ec84f71d09129434b044246sewardj         assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
11131e5854d6d470f21677ec84f71d09129434b044246sewardj         assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
11132e5854d6d470f21677ec84f71d09129434b044246sewardj         t5 = newTemp(Ity_I32);
11133e13074c2c1321d069fb95806bdce64f9a3512341sewardj         assign(t5,
11134e13074c2c1321d069fb95806bdce64f9a3512341sewardj                unop(Iop_16Uto32,
11135e13074c2c1321d069fb95806bdce64f9a3512341sewardj                     binop(Iop_8HLto16,
11136e13074c2c1321d069fb95806bdce64f9a3512341sewardj                           unop(Iop_GetMSBs8x8, mkexpr(t1)),
11137e13074c2c1321d069fb95806bdce64f9a3512341sewardj                           unop(Iop_GetMSBs8x8, mkexpr(t0)))));
11138e5854d6d470f21677ec84f71d09129434b044246sewardj         putIReg(4, gregOfRM(modrm), mkexpr(t5));
11139e5854d6d470f21677ec84f71d09129434b044246sewardj         DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11140e5854d6d470f21677ec84f71d09129434b044246sewardj                                 nameIReg(4,gregOfRM(modrm)));
11141e5854d6d470f21677ec84f71d09129434b044246sewardj         delta += 3;
11142e5854d6d470f21677ec84f71d09129434b044246sewardj         goto decode_success;
11143e5854d6d470f21677ec84f71d09129434b044246sewardj      }
11144e5854d6d470f21677ec84f71d09129434b044246sewardj      /* else fall through */
11145e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11146e5854d6d470f21677ec84f71d09129434b044246sewardj
11147e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
11148e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
11149e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11150e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pmulhuw", Iop_MulHi16Ux8, False );
11151e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11152e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11153e5854d6d470f21677ec84f71d09129434b044246sewardj
11154e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
11155e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
11156e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11157e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pmulhw", Iop_MulHi16Sx8, False );
11158e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11159e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11160e5854d6d470f21677ec84f71d09129434b044246sewardj
11161e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F D5 = PMULHL -- 16x8 multiply */
11162e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
11163e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11164e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pmullw", Iop_Mul16x8, False );
11165e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11166e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11167e5854d6d470f21677ec84f71d09129434b044246sewardj
11168e5854d6d470f21677ec84f71d09129434b044246sewardj   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11169e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11170e5854d6d470f21677ec84f71d09129434b044246sewardj      0 to form 64-bit result */
11171e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
11172e5854d6d470f21677ec84f71d09129434b044246sewardj      IRTemp sV = newTemp(Ity_I64);
11173e5854d6d470f21677ec84f71d09129434b044246sewardj      IRTemp dV = newTemp(Ity_I64);
11174e5854d6d470f21677ec84f71d09129434b044246sewardj      t1 = newTemp(Ity_I32);
11175e5854d6d470f21677ec84f71d09129434b044246sewardj      t0 = newTemp(Ity_I32);
11176e5854d6d470f21677ec84f71d09129434b044246sewardj      modrm = insn[2];
11177e5854d6d470f21677ec84f71d09129434b044246sewardj
11178e5854d6d470f21677ec84f71d09129434b044246sewardj      do_MMX_preamble();
11179e5854d6d470f21677ec84f71d09129434b044246sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
11180e5854d6d470f21677ec84f71d09129434b044246sewardj
11181e5854d6d470f21677ec84f71d09129434b044246sewardj      if (epartIsReg(modrm)) {
11182e5854d6d470f21677ec84f71d09129434b044246sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
11183e5854d6d470f21677ec84f71d09129434b044246sewardj         delta += 2+1;
11184e5854d6d470f21677ec84f71d09129434b044246sewardj         DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
11185e5854d6d470f21677ec84f71d09129434b044246sewardj                                nameMMXReg(gregOfRM(modrm)));
11186e5854d6d470f21677ec84f71d09129434b044246sewardj      } else {
11187e5854d6d470f21677ec84f71d09129434b044246sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11188e5854d6d470f21677ec84f71d09129434b044246sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11189e5854d6d470f21677ec84f71d09129434b044246sewardj         delta += 2+alen;
11190e5854d6d470f21677ec84f71d09129434b044246sewardj         DIP("pmuludq %s,%s\n", dis_buf,
11191e5854d6d470f21677ec84f71d09129434b044246sewardj                                nameMMXReg(gregOfRM(modrm)));
11192e5854d6d470f21677ec84f71d09129434b044246sewardj      }
11193e5854d6d470f21677ec84f71d09129434b044246sewardj
11194e5854d6d470f21677ec84f71d09129434b044246sewardj      assign( t0, unop(Iop_64to32, mkexpr(dV)) );
11195e5854d6d470f21677ec84f71d09129434b044246sewardj      assign( t1, unop(Iop_64to32, mkexpr(sV)) );
11196e5854d6d470f21677ec84f71d09129434b044246sewardj      putMMXReg( gregOfRM(modrm),
11197e5854d6d470f21677ec84f71d09129434b044246sewardj                 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
11198e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11199e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11200e5854d6d470f21677ec84f71d09129434b044246sewardj
11201e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11202e5854d6d470f21677ec84f71d09129434b044246sewardj      0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
11203e5854d6d470f21677ec84f71d09129434b044246sewardj      half */
11204e5854d6d470f21677ec84f71d09129434b044246sewardj   /* This is a really poor translation -- could be improved if
11205e5854d6d470f21677ec84f71d09129434b044246sewardj      performance critical */
11206e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
11207e5854d6d470f21677ec84f71d09129434b044246sewardj      IRTemp sV, dV;
11208e5854d6d470f21677ec84f71d09129434b044246sewardj      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
11209e5854d6d470f21677ec84f71d09129434b044246sewardj      sV = newTemp(Ity_V128);
11210e5854d6d470f21677ec84f71d09129434b044246sewardj      dV = newTemp(Ity_V128);
11211e5854d6d470f21677ec84f71d09129434b044246sewardj      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
11212e5854d6d470f21677ec84f71d09129434b044246sewardj      t1 = newTemp(Ity_I64);
11213e5854d6d470f21677ec84f71d09129434b044246sewardj      t0 = newTemp(Ity_I64);
11214e5854d6d470f21677ec84f71d09129434b044246sewardj      modrm = insn[2];
11215e5854d6d470f21677ec84f71d09129434b044246sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
11216e5854d6d470f21677ec84f71d09129434b044246sewardj
11217e5854d6d470f21677ec84f71d09129434b044246sewardj      if (epartIsReg(modrm)) {
11218e5854d6d470f21677ec84f71d09129434b044246sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
11219e5854d6d470f21677ec84f71d09129434b044246sewardj         delta += 2+1;
11220e5854d6d470f21677ec84f71d09129434b044246sewardj         DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11221e5854d6d470f21677ec84f71d09129434b044246sewardj                                nameXMMReg(gregOfRM(modrm)));
11222e5854d6d470f21677ec84f71d09129434b044246sewardj      } else {
11223e5854d6d470f21677ec84f71d09129434b044246sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11224e5854d6d470f21677ec84f71d09129434b044246sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11225e5854d6d470f21677ec84f71d09129434b044246sewardj         delta += 2+alen;
11226e5854d6d470f21677ec84f71d09129434b044246sewardj         DIP("pmuludq %s,%s\n", dis_buf,
11227e5854d6d470f21677ec84f71d09129434b044246sewardj                                nameXMMReg(gregOfRM(modrm)));
11228e5854d6d470f21677ec84f71d09129434b044246sewardj      }
11229e5854d6d470f21677ec84f71d09129434b044246sewardj
11230e5854d6d470f21677ec84f71d09129434b044246sewardj      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
11231e5854d6d470f21677ec84f71d09129434b044246sewardj      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11232e5854d6d470f21677ec84f71d09129434b044246sewardj
11233e5854d6d470f21677ec84f71d09129434b044246sewardj      assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
11234e5854d6d470f21677ec84f71d09129434b044246sewardj      putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
11235e5854d6d470f21677ec84f71d09129434b044246sewardj      assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
11236e5854d6d470f21677ec84f71d09129434b044246sewardj      putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
11237e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11238e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11239e5854d6d470f21677ec84f71d09129434b044246sewardj
11240e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F EB = POR */
11241e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
11242f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_OrV128 );
11243e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11244e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11245e5854d6d470f21677ec84f71d09129434b044246sewardj
112467b5b9983870e937182d0a3a411047397257310b3sewardj   /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
112477b5b9983870e937182d0a3a411047397257310b3sewardj      from E(xmm or mem) to G(xmm) */
112487b5b9983870e937182d0a3a411047397257310b3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF6) {
112497b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp s1V  = newTemp(Ity_V128);
112507b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp s2V  = newTemp(Ity_V128);
112517b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp dV   = newTemp(Ity_V128);
112527b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp s1Hi = newTemp(Ity_I64);
112537b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp s1Lo = newTemp(Ity_I64);
112547b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp s2Hi = newTemp(Ity_I64);
112557b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp s2Lo = newTemp(Ity_I64);
112567b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp dHi  = newTemp(Ity_I64);
112577b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp dLo  = newTemp(Ity_I64);
112587b5b9983870e937182d0a3a411047397257310b3sewardj      modrm = insn[2];
112597b5b9983870e937182d0a3a411047397257310b3sewardj      if (epartIsReg(modrm)) {
112607b5b9983870e937182d0a3a411047397257310b3sewardj         assign( s1V, getXMMReg(eregOfRM(modrm)) );
112617b5b9983870e937182d0a3a411047397257310b3sewardj         delta += 2+1;
112627b5b9983870e937182d0a3a411047397257310b3sewardj         DIP("psadbw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
112637b5b9983870e937182d0a3a411047397257310b3sewardj                               nameXMMReg(gregOfRM(modrm)));
112647b5b9983870e937182d0a3a411047397257310b3sewardj      } else {
112657b5b9983870e937182d0a3a411047397257310b3sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
112667b5b9983870e937182d0a3a411047397257310b3sewardj         assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
112677b5b9983870e937182d0a3a411047397257310b3sewardj         delta += 2+alen;
112687b5b9983870e937182d0a3a411047397257310b3sewardj         DIP("psadbw %s,%s\n", dis_buf,
112697b5b9983870e937182d0a3a411047397257310b3sewardj                               nameXMMReg(gregOfRM(modrm)));
112707b5b9983870e937182d0a3a411047397257310b3sewardj      }
112717b5b9983870e937182d0a3a411047397257310b3sewardj      assign( s2V, getXMMReg(gregOfRM(modrm)) );
112727b5b9983870e937182d0a3a411047397257310b3sewardj      assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
112737b5b9983870e937182d0a3a411047397257310b3sewardj      assign( s1Lo, unop(Iop_V128to64,   mkexpr(s1V)) );
112747b5b9983870e937182d0a3a411047397257310b3sewardj      assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
112757b5b9983870e937182d0a3a411047397257310b3sewardj      assign( s2Lo, unop(Iop_V128to64,   mkexpr(s2V)) );
112767b5b9983870e937182d0a3a411047397257310b3sewardj      assign( dHi, mkIRExprCCall(
112777b5b9983870e937182d0a3a411047397257310b3sewardj                      Ity_I64, 0/*regparms*/,
112787b5b9983870e937182d0a3a411047397257310b3sewardj                      "x86g_calculate_mmx_psadbw",
112797b5b9983870e937182d0a3a411047397257310b3sewardj                      &x86g_calculate_mmx_psadbw,
112807b5b9983870e937182d0a3a411047397257310b3sewardj                      mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
112817b5b9983870e937182d0a3a411047397257310b3sewardj                   ));
112827b5b9983870e937182d0a3a411047397257310b3sewardj      assign( dLo, mkIRExprCCall(
112837b5b9983870e937182d0a3a411047397257310b3sewardj                      Ity_I64, 0/*regparms*/,
112847b5b9983870e937182d0a3a411047397257310b3sewardj                      "x86g_calculate_mmx_psadbw",
112857b5b9983870e937182d0a3a411047397257310b3sewardj                      &x86g_calculate_mmx_psadbw,
112867b5b9983870e937182d0a3a411047397257310b3sewardj                      mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
112877b5b9983870e937182d0a3a411047397257310b3sewardj                   ));
112887b5b9983870e937182d0a3a411047397257310b3sewardj      assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
112897b5b9983870e937182d0a3a411047397257310b3sewardj      putXMMReg(gregOfRM(modrm), mkexpr(dV));
112907b5b9983870e937182d0a3a411047397257310b3sewardj      goto decode_success;
112917b5b9983870e937182d0a3a411047397257310b3sewardj   }
112927b5b9983870e937182d0a3a411047397257310b3sewardj
11293b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
11294b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
11295b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      Int order;
11296b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      IRTemp sV, dV, s3, s2, s1, s0;
11297b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11298b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      sV = newTemp(Ity_V128);
11299b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      dV = newTemp(Ity_V128);
11300b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      modrm = insn[2];
11301b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      if (epartIsReg(modrm)) {
11302b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
11303b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         order = (Int)insn[3];
11304b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         delta += 2+2;
11305b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         DIP("pshufd $%d,%s,%s\n", order,
11306b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                   nameXMMReg(eregOfRM(modrm)),
11307b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                   nameXMMReg(gregOfRM(modrm)));
11308b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      } else {
11309b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11310b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11311b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj	 order = (Int)insn[2+alen];
11312b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         delta += 3+alen;
11313b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         DIP("pshufd $%d,%s,%s\n", order,
11314b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                   dis_buf,
11315b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                   nameXMMReg(gregOfRM(modrm)));
11316b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      }
11317b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11318b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11319b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj#     define SEL(n) \
11320b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11321b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      assign(dV,
11322b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj	     mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
11323b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                           SEL((order>>2)&3), SEL((order>>0)&3) )
11324b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      );
11325b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11326b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj#     undef SEL
11327b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11328b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11329b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11330b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
11331b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      mem) to G(xmm), and copy lower half */
11332b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
11333b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      Int order;
11334b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
11335b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11336b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      sV   = newTemp(Ity_V128);
11337b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      dV   = newTemp(Ity_V128);
11338b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      sVhi = newTemp(Ity_I64);
11339b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      dVhi = newTemp(Ity_I64);
11340b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      modrm = insn[3];
11341b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      if (epartIsReg(modrm)) {
11342b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
11343b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         order = (Int)insn[4];
11344b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         delta += 4+1;
11345b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         DIP("pshufhw $%d,%s,%s\n", order,
11346b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    nameXMMReg(eregOfRM(modrm)),
11347b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    nameXMMReg(gregOfRM(modrm)));
11348b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      } else {
11349b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11350b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11351b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj	 order = (Int)insn[3+alen];
11352b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         delta += 4+alen;
11353b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         DIP("pshufhw $%d,%s,%s\n", order,
11354b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    dis_buf,
11355b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    nameXMMReg(gregOfRM(modrm)));
11356b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      }
11357f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
11358b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
11359b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11360b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj#     define SEL(n) \
11361b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11362b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      assign(dVhi,
11363b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11364b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                          SEL((order>>2)&3), SEL((order>>0)&3) )
11365b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      );
11366f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign(dV, binop( Iop_64HLtoV128,
11367b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                        mkexpr(dVhi),
11368f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                        unop(Iop_V128to64, mkexpr(sV))) );
11369b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11370b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj#     undef SEL
11371b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11372b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11373b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11374b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
11375b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      mem) to G(xmm), and copy upper half */
11376b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
11377b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      Int order;
11378b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
11379b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11380b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      sV   = newTemp(Ity_V128);
11381b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      dV   = newTemp(Ity_V128);
11382b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      sVlo = newTemp(Ity_I64);
11383b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      dVlo = newTemp(Ity_I64);
11384b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      modrm = insn[3];
11385b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      if (epartIsReg(modrm)) {
11386b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
11387b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         order = (Int)insn[4];
11388b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         delta += 4+1;
11389b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         DIP("pshuflw $%d,%s,%s\n", order,
11390b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    nameXMMReg(eregOfRM(modrm)),
11391b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    nameXMMReg(gregOfRM(modrm)));
11392b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      } else {
11393b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11394b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11395b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj	 order = (Int)insn[3+alen];
11396b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         delta += 4+alen;
11397b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         DIP("pshuflw $%d,%s,%s\n", order,
11398b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    dis_buf,
11399b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    nameXMMReg(gregOfRM(modrm)));
11400b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      }
11401f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
11402b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
11403b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11404b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj#     define SEL(n) \
11405b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11406b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      assign(dVlo,
11407b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11408b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                          SEL((order>>2)&3), SEL((order>>0)&3) )
11409b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      );
11410f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign(dV, binop( Iop_64HLtoV128,
11411f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                        unop(Iop_V128HIto64, mkexpr(sV)),
11412b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                        mkexpr(dVlo) ) );
11413b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11414b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj#     undef SEL
11415b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11416b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11417b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11418b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 72 /6 ib = PSLLD by immediate */
11419b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11420b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11421b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 6) {
1142238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
11423b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11424b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11425b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11426b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F F2 = PSLLD by E */
11427b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
11428b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
11429b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11430b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11431b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11432b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 73 /7 ib = PSLLDQ by immediate */
11433b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11434b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11435b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 7) {
114360c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
114370c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      Int    imm = (Int)insn[3];
114380c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      Int    reg = eregOfRM(insn[2]);
114390c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
114400c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      vassert(imm >= 0 && imm <= 255);
114410c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      delta += 4;
114420c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj
114430c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      sV    = newTemp(Ity_V128);
114440c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      dV    = newTemp(Ity_V128);
114450c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      hi64  = newTemp(Ity_I64);
114460c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      lo64  = newTemp(Ity_I64);
114470c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      hi64r = newTemp(Ity_I64);
114480c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      lo64r = newTemp(Ity_I64);
114490c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj
114500c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      if (imm >= 16) {
114510c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         putXMMReg(reg, mkV128(0x0000));
114520c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         goto decode_success;
114530c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      }
114540c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj
114550c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      assign( sV, getXMMReg(reg) );
11456f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11457f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
114580c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj
11459ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      if (imm == 0) {
11460ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj         assign( lo64r, mkexpr(lo64) );
11461ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj         assign( hi64r, mkexpr(hi64) );
11462ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      }
11463ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      else
114640c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      if (imm == 8) {
114650c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         assign( lo64r, mkU64(0) );
114660c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         assign( hi64r, mkexpr(lo64) );
114670c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      }
11468c02043c8887e97cf6e9ae02a02edd3a84d92fb58sewardj      else
114690c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      if (imm > 8) {
114700c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         assign( lo64r, mkU64(0) );
114710c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         assign( hi64r, binop( Iop_Shl64,
114720c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                               mkexpr(lo64),
114730c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                               mkU8( 8*(imm-8) ) ));
114740c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      } else {
114750c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         assign( lo64r, binop( Iop_Shl64,
114760c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                               mkexpr(lo64),
114770c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                               mkU8(8 * imm) ));
114780c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         assign( hi64r,
114790c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                 binop( Iop_Or64,
114800c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                        binop(Iop_Shl64, mkexpr(hi64),
114810c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                                         mkU8(8 * imm)),
114820c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                        binop(Iop_Shr64, mkexpr(lo64),
114830c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                                         mkU8(8 * (8 - imm)) )
114840c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                      )
114850c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj               );
114860c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      }
11487f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
114880c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      putXMMReg(reg, mkexpr(dV));
11489b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11490b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11491b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11492b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 73 /6 ib = PSLLQ by immediate */
11493b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11494b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11495b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 6) {
1149638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
11497b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11498b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11499b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11500b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F F3 = PSLLQ by E */
11501b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
11502b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
11503b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11504b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11505b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11506b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 71 /6 ib = PSLLW by immediate */
11507b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11508b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11509b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 6) {
1151038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
11511b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11512b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11513b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11514b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F F1 = PSLLW by E */
11515b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
11516b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
11517b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11518b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11519b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11520b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 72 /4 ib = PSRAD by immediate */
11521b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11522b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11523b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 4) {
1152438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
11525b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11526b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11527b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11528b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F E2 = PSRAD by E */
11529b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
11530b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
11531b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11532b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11533b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11534b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 71 /4 ib = PSRAW by immediate */
11535b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11536b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11537b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 4) {
1153838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
11539b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11540b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11541b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11542b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F E1 = PSRAW by E */
11543b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
11544b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
11545b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11546b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11547b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11548b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 72 /2 ib = PSRLD by immediate */
11549b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11550b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11551b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 2) {
1155238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
11553b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11554b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11555b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11556b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F D2 = PSRLD by E */
11557b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
11558b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
11559b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11560b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11561b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
115629ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj   /* 66 0F 73 /3 ib = PSRLDQ by immediate */
115639ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
115649ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj       && epartIsReg(insn[2])
1156595535feeb27c5641608bc9eb83c047837281a7f4sewardj       && gregOfRM(insn[2]) == 3) {
1156695535feeb27c5641608bc9eb83c047837281a7f4sewardj      IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
115679ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      Int    imm = (Int)insn[3];
115689ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      Int    reg = eregOfRM(insn[2]);
1156995535feeb27c5641608bc9eb83c047837281a7f4sewardj      DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
1157095535feeb27c5641608bc9eb83c047837281a7f4sewardj      vassert(imm >= 0 && imm <= 255);
115719ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      delta += 4;
1157295535feeb27c5641608bc9eb83c047837281a7f4sewardj
1157395535feeb27c5641608bc9eb83c047837281a7f4sewardj      sV    = newTemp(Ity_V128);
1157495535feeb27c5641608bc9eb83c047837281a7f4sewardj      dV    = newTemp(Ity_V128);
1157595535feeb27c5641608bc9eb83c047837281a7f4sewardj      hi64  = newTemp(Ity_I64);
1157695535feeb27c5641608bc9eb83c047837281a7f4sewardj      lo64  = newTemp(Ity_I64);
1157795535feeb27c5641608bc9eb83c047837281a7f4sewardj      hi64r = newTemp(Ity_I64);
1157895535feeb27c5641608bc9eb83c047837281a7f4sewardj      lo64r = newTemp(Ity_I64);
1157995535feeb27c5641608bc9eb83c047837281a7f4sewardj
1158095535feeb27c5641608bc9eb83c047837281a7f4sewardj      if (imm >= 16) {
1158195535feeb27c5641608bc9eb83c047837281a7f4sewardj         putXMMReg(reg, mkV128(0x0000));
1158295535feeb27c5641608bc9eb83c047837281a7f4sewardj         goto decode_success;
1158395535feeb27c5641608bc9eb83c047837281a7f4sewardj      }
1158495535feeb27c5641608bc9eb83c047837281a7f4sewardj
115859ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      assign( sV, getXMMReg(reg) );
11586f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11587f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
1158895535feeb27c5641608bc9eb83c047837281a7f4sewardj
11589ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      if (imm == 0) {
11590ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj         assign( lo64r, mkexpr(lo64) );
11591ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj         assign( hi64r, mkexpr(hi64) );
11592ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      }
11593ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      else
1159495535feeb27c5641608bc9eb83c047837281a7f4sewardj      if (imm == 8) {
1159595535feeb27c5641608bc9eb83c047837281a7f4sewardj         assign( hi64r, mkU64(0) );
1159695535feeb27c5641608bc9eb83c047837281a7f4sewardj         assign( lo64r, mkexpr(hi64) );
1159795535feeb27c5641608bc9eb83c047837281a7f4sewardj      }
1159895535feeb27c5641608bc9eb83c047837281a7f4sewardj      else
1159995535feeb27c5641608bc9eb83c047837281a7f4sewardj      if (imm > 8) {
1160095535feeb27c5641608bc9eb83c047837281a7f4sewardj         assign( hi64r, mkU64(0) );
1160195535feeb27c5641608bc9eb83c047837281a7f4sewardj         assign( lo64r, binop( Iop_Shr64,
1160295535feeb27c5641608bc9eb83c047837281a7f4sewardj                               mkexpr(hi64),
1160395535feeb27c5641608bc9eb83c047837281a7f4sewardj                               mkU8( 8*(imm-8) ) ));
1160495535feeb27c5641608bc9eb83c047837281a7f4sewardj      } else {
1160595535feeb27c5641608bc9eb83c047837281a7f4sewardj         assign( hi64r, binop( Iop_Shr64,
1160695535feeb27c5641608bc9eb83c047837281a7f4sewardj                               mkexpr(hi64),
1160795535feeb27c5641608bc9eb83c047837281a7f4sewardj                               mkU8(8 * imm) ));
1160895535feeb27c5641608bc9eb83c047837281a7f4sewardj         assign( lo64r,
1160995535feeb27c5641608bc9eb83c047837281a7f4sewardj                 binop( Iop_Or64,
1161095535feeb27c5641608bc9eb83c047837281a7f4sewardj                        binop(Iop_Shr64, mkexpr(lo64),
1161195535feeb27c5641608bc9eb83c047837281a7f4sewardj                                         mkU8(8 * imm)),
1161295535feeb27c5641608bc9eb83c047837281a7f4sewardj                        binop(Iop_Shl64, mkexpr(hi64),
1161395535feeb27c5641608bc9eb83c047837281a7f4sewardj                                         mkU8(8 * (8 - imm)) )
1161495535feeb27c5641608bc9eb83c047837281a7f4sewardj                      )
1161595535feeb27c5641608bc9eb83c047837281a7f4sewardj               );
1161695535feeb27c5641608bc9eb83c047837281a7f4sewardj      }
1161795535feeb27c5641608bc9eb83c047837281a7f4sewardj
11618f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
116199ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      putXMMReg(reg, mkexpr(dV));
116209ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      goto decode_success;
116219ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj   }
116229ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj
11623b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 73 /2 ib = PSRLQ by immediate */
11624b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11625b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11626b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 2) {
1162738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
11628b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11629b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11630b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11631b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F D3 = PSRLQ by E */
11632b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
11633b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
11634b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11635b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11636b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11637b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 71 /2 ib = PSRLW by immediate */
11638b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11639b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11640b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 2) {
1164138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
11642b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11643b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11644b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11645b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F D1 = PSRLW by E */
11646b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
11647b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
11648b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11649b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11650b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11651b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F F8 = PSUBB */
11652b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
11653b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11654b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubb", Iop_Sub8x16, False );
11655b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11656b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11657b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11658b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F FA = PSUBD */
11659b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
11660b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11661b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubd", Iop_Sub32x4, False );
11662b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11663b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11664b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11665b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11666b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 0F FB = PSUBQ -- sub 64x1 */
11667b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
11668b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      do_MMX_preamble();
11669b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_MMXop_regmem_to_reg (
11670b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                sorb, delta+2, insn[1], "psubq", False );
11671b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11672b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11673b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11674b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F FB = PSUBQ */
11675b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
11676b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11677b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubq", Iop_Sub64x2, False );
11678b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11679b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11680b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11681b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F F9 = PSUBW */
11682b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
11683b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11684b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubw", Iop_Sub16x8, False );
11685b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11686b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11687b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11688b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F E8 = PSUBSB */
11689b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
11690b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11691b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubsb", Iop_QSub8Sx16, False );
11692b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11693b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11694b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11695b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F E9 = PSUBSW */
11696b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
11697b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11698b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubsw", Iop_QSub16Sx8, False );
11699b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11700b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11701b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11702b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F D8 = PSUBSB */
11703b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
11704b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11705b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubusb", Iop_QSub8Ux16, False );
11706b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11707b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11708b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11709b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F D9 = PSUBSW */
11710b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
11711b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11712b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubusw", Iop_QSub16Ux8, False );
11713b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11714b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11715b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
117169e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 68 = PUNPCKHBW */
117179e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
117189e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
117199e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpckhbw",
117209e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveHI8x16, True );
117219e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117229e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117239e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
117249e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 6A = PUNPCKHDQ */
117259e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
117269e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
117279e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpckhdq",
117289e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveHI32x4, True );
117299e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117309e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117319e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
117329e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 6D = PUNPCKHQDQ */
117339e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
117349e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
117359e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpckhqdq",
117369e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveHI64x2, True );
117379e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117389e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117399e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
117409e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 69 = PUNPCKHWD */
117419e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
117429e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
117439e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpckhwd",
117449e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveHI16x8, True );
117459e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117469e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117479e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
117489e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 60 = PUNPCKLBW */
117499e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
117509e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
117519e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpcklbw",
117529e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveLO8x16, True );
117539e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117549e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117559e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
117569e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 62 = PUNPCKLDQ */
117579e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
117589e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
117599e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpckldq",
117609e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveLO32x4, True );
117619e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117629e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117639e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
117649e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 6C = PUNPCKLQDQ */
117659e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
117669e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
117679e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpcklqdq",
117689e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveLO64x2, True );
117699e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117709e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117719e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
117729e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 61 = PUNPCKLWD */
117739e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
117749e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
117759e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpcklwd",
117769e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveLO16x8, True );
117779e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117789e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117799e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
117809e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F EF = PXOR */
117819e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
11782f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_XorV128 );
117839e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117849e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117859e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
11786c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--    /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11787c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--    if (insn[0] == 0x0F && insn[1] == 0xAE
11788c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--        && (!epartIsReg(insn[2]))
11789c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--        && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11790c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       Bool store = gregOfRM(insn[2]) == 0;
11791c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       vg_assert(sz == 4);
11792c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       pair = disAMode ( cb, sorb, eip+2, dis_buf );
11793c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       t1   = LOW24(pair);
11794c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       eip += 2+HI8(pair);
11795c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11796c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--                   Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11797c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--                   Lit16, (UShort)insn[2],
11798c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--                   TempReg, t1 );
11799c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11800c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       goto decode_success;
11801c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--    }
11802c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
11803bfceb089644ce9eee882bae5cec5902be4831cacsewardj   /* 0F AE /7 = CLFLUSH -- flush cache line */
11804bfceb089644ce9eee882bae5cec5902be4831cacsewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
11805bfceb089644ce9eee882bae5cec5902be4831cacsewardj       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
11806bfceb089644ce9eee882bae5cec5902be4831cacsewardj
11807bfceb089644ce9eee882bae5cec5902be4831cacsewardj      /* This is something of a hack.  We need to know the size of the
11808bfceb089644ce9eee882bae5cec5902be4831cacsewardj         cache line containing addr.  Since we don't (easily), assume
11809bfceb089644ce9eee882bae5cec5902be4831cacsewardj         256 on the basis that no real cache would have a line that
11810bfceb089644ce9eee882bae5cec5902be4831cacsewardj         big.  It's safe to invalidate more stuff than we need, just
11811bfceb089644ce9eee882bae5cec5902be4831cacsewardj         inefficient. */
11812bfceb089644ce9eee882bae5cec5902be4831cacsewardj      UInt lineszB = 256;
11813bfceb089644ce9eee882bae5cec5902be4831cacsewardj
11814bfceb089644ce9eee882bae5cec5902be4831cacsewardj      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11815bfceb089644ce9eee882bae5cec5902be4831cacsewardj      delta += 2+alen;
11816bfceb089644ce9eee882bae5cec5902be4831cacsewardj
11817bfceb089644ce9eee882bae5cec5902be4831cacsewardj      /* Round addr down to the start of the containing block. */
11818bfceb089644ce9eee882bae5cec5902be4831cacsewardj      stmt( IRStmt_Put(
1181905f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj               OFFB_CMSTART,
11820bfceb089644ce9eee882bae5cec5902be4831cacsewardj               binop( Iop_And32,
11821bfceb089644ce9eee882bae5cec5902be4831cacsewardj                      mkexpr(addr),
11822bfceb089644ce9eee882bae5cec5902be4831cacsewardj                      mkU32( ~(lineszB-1) ))) );
11823bfceb089644ce9eee882bae5cec5902be4831cacsewardj
1182405f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj      stmt( IRStmt_Put(OFFB_CMLEN, mkU32(lineszB) ) );
11825bfceb089644ce9eee882bae5cec5902be4831cacsewardj
1182605f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj      jmp_lit(&dres, Ijk_InvalICache, (Addr32)(guest_EIP_bbstart+delta));
11827bfceb089644ce9eee882bae5cec5902be4831cacsewardj
11828bfceb089644ce9eee882bae5cec5902be4831cacsewardj      DIP("clflush %s\n", dis_buf);
11829bfceb089644ce9eee882bae5cec5902be4831cacsewardj      goto decode_success;
11830bfceb089644ce9eee882bae5cec5902be4831cacsewardj   }
11831c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
11832c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* ---------------------------------------------------- */
1183390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* --- end of the SSE2 decoder.                     --- */
1183490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* ---------------------------------------------------- */
1183590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1183690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* ---------------------------------------------------- */
1183790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* --- start of the SSE3 decoder.                   --- */
1183890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* ---------------------------------------------------- */
1183990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1184090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* Skip parts of the decoder which don't apply given the stated
1184190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      guest subarchitecture. */
118429f07e86cdca623c4c894a6864af0f936c685ea8fflorian   if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE3))
118435117ce116f47141cb23d1b49cc826e19323add97sewardj      goto after_sse_decoders; /* no SSE3 capabilities */
1184490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
118458462d113e3efeacceb304222dada8d85f748295aflorian   insn = &guest_code[delta];
1184690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1184790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
1184890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      duplicating some lanes (2:2:0:0). */
1184990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
1185090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      duplicating some lanes (3:3:1:1). */
1185190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   if (sz == 4 && insn[0] == 0xF3 && insn[1] == 0x0F
1185290e91ee4a7b941c39e6f6df94fedf02649b14695sewardj       && (insn[2] == 0x12 || insn[2] == 0x16)) {
1185390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp s3, s2, s1, s0;
1185490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp sV  = newTemp(Ity_V128);
1185590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      Bool   isH = insn[2] == 0x16;
1185690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      s3 = s2 = s1 = s0 = IRTemp_INVALID;
1185790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1185890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      modrm = insn[3];
1185990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      if (epartIsReg(modrm)) {
1186090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         assign( sV, getXMMReg( eregOfRM(modrm)) );
1186190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
1186290e91ee4a7b941c39e6f6df94fedf02649b14695sewardj                                  nameXMMReg(eregOfRM(modrm)),
1186390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj                                  nameXMMReg(gregOfRM(modrm)));
1186490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         delta += 3+1;
1186590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      } else {
1186690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
1186745ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj         gen_SEGV_if_not_16_aligned( addr );
1186890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
1186990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
1187090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj	     dis_buf,
1187190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj             nameXMMReg(gregOfRM(modrm)));
1187290e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         delta += 3+alen;
1187390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      }
1187490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1187590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
1187690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      putXMMReg( gregOfRM(modrm),
1187790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj                 isH ? mk128from32s( s3, s3, s1, s1 )
1187890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj                     : mk128from32s( s2, s2, s0, s0 ) );
1187990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      goto decode_success;
1188090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   }
1188190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
11882dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
11883dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      duplicating some lanes (0:1:0:1). */
11884dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x12) {
11885dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp sV = newTemp(Ity_V128);
11886dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp d0 = newTemp(Ity_I64);
11887dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11888dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      modrm = insn[3];
11889dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      if (epartIsReg(modrm)) {
11890dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( sV, getXMMReg( eregOfRM(modrm)) );
11891dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("movddup %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11892dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                nameXMMReg(gregOfRM(modrm)));
11893dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 3+1;
11894dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
11895dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      } else {
11896dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11897dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
11898dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("movddup %s,%s\n", dis_buf,
11899dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                nameXMMReg(gregOfRM(modrm)));
11900dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 3+alen;
11901dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      }
11902dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11903dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      putXMMReg( gregOfRM(modrm), binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
11904dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      goto decode_success;
11905dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   }
11906dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
1190790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
1190890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD0) {
1190990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
1191090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp eV   = newTemp(Ity_V128);
1191190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp gV   = newTemp(Ity_V128);
1191290e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp addV = newTemp(Ity_V128);
1191390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp subV = newTemp(Ity_V128);
119149571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      IRTemp rm     = newTemp(Ity_I32);
1191590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
1191690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1191790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      modrm = insn[3];
1191890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      if (epartIsReg(modrm)) {
1191990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         assign( eV, getXMMReg( eregOfRM(modrm)) );
1192090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         DIP("addsubps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
1192190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj                                 nameXMMReg(gregOfRM(modrm)));
1192290e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         delta += 3+1;
1192390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      } else {
1192490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
1192590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
1192690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         DIP("addsubps %s,%s\n", dis_buf,
1192790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj                                 nameXMMReg(gregOfRM(modrm)));
1192890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         delta += 3+alen;
1192990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      }
1193090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1193190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      assign( gV, getXMMReg(gregOfRM(modrm)) );
1193290e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
119339571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
119349571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( addV, triop(Iop_Add32Fx4, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
119359571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( subV, triop(Iop_Sub32Fx4, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
1193690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1193790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      breakup128to32s( addV, &a3, &a2, &a1, &a0 );
1193890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      breakup128to32s( subV, &s3, &s2, &s1, &s0 );
1193990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1194090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      putXMMReg( gregOfRM(modrm), mk128from32s( a3, s2, a1, s0 ));
1194190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      goto decode_success;
1194290e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   }
1194390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
11944dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
11945dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD0) {
11946dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp eV   = newTemp(Ity_V128);
11947dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp gV   = newTemp(Ity_V128);
11948dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp addV = newTemp(Ity_V128);
11949dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp subV = newTemp(Ity_V128);
11950dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp a1     = newTemp(Ity_I64);
11951dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp s0     = newTemp(Ity_I64);
119529571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      IRTemp rm     = newTemp(Ity_I32);
11953dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11954dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      modrm = insn[2];
11955dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      if (epartIsReg(modrm)) {
11956dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( eV, getXMMReg( eregOfRM(modrm)) );
11957dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11958dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                 nameXMMReg(gregOfRM(modrm)));
11959dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 2+1;
11960dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      } else {
11961dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11962dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11963dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("addsubpd %s,%s\n", dis_buf,
11964dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                 nameXMMReg(gregOfRM(modrm)));
11965dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 2+alen;
11966dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      }
11967dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11968dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( gV, getXMMReg(gregOfRM(modrm)) );
11969dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
119709571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
119719571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( addV, triop(Iop_Add64Fx2, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
119729571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( subV, triop(Iop_Sub64Fx2, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
11973dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11974dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
11975dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( s0, unop(Iop_V128to64,   mkexpr(subV) ));
11976dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11977dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      putXMMReg( gregOfRM(modrm),
11978dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
11979dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      goto decode_success;
11980dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   }
11981dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11982dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
11983dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
11984dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F
11985dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj       && (insn[2] == 0x7C || insn[2] == 0x7D)) {
11986dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
11987dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp eV     = newTemp(Ity_V128);
11988dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp gV     = newTemp(Ity_V128);
11989dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp leftV  = newTemp(Ity_V128);
11990dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp rightV = newTemp(Ity_V128);
119919571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      IRTemp rm     = newTemp(Ity_I32);
11992dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      Bool   isAdd  = insn[2] == 0x7C;
1199355085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = isAdd ? "add" : "sub";
11994dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
11995dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11996dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      modrm = insn[3];
11997dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      if (epartIsReg(modrm)) {
11998dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( eV, getXMMReg( eregOfRM(modrm)) );
11999dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12000dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                   nameXMMReg(gregOfRM(modrm)));
12001dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 3+1;
12002dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      } else {
12003dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12004dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12005dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("h%sps %s,%s\n", str, dis_buf,
12006dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                   nameXMMReg(gregOfRM(modrm)));
12007dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 3+alen;
12008dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      }
12009dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
12010dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( gV, getXMMReg(gregOfRM(modrm)) );
12011dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
12012dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      breakup128to32s( eV, &e3, &e2, &e1, &e0 );
12013dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      breakup128to32s( gV, &g3, &g2, &g1, &g0 );
12014dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
12015dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( leftV,  mk128from32s( e2, e0, g2, g0 ) );
12016dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
12017dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
120189571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
12019dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      putXMMReg( gregOfRM(modrm),
120209571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                 triop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
120219571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                       mkexpr(rm), mkexpr(leftV), mkexpr(rightV) ) );
12022dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      goto decode_success;
12023dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   }
12024dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
12025dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
12026dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
12027dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
12028dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp e1     = newTemp(Ity_I64);
12029dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp e0     = newTemp(Ity_I64);
12030dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp g1     = newTemp(Ity_I64);
12031dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp g0     = newTemp(Ity_I64);
12032dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp eV     = newTemp(Ity_V128);
12033dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp gV     = newTemp(Ity_V128);
12034dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp leftV  = newTemp(Ity_V128);
12035dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp rightV = newTemp(Ity_V128);
120369571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      IRTemp rm     = newTemp(Ity_I32);
12037dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      Bool   isAdd  = insn[1] == 0x7C;
1203855085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = isAdd ? "add" : "sub";
12039dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
12040dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      modrm = insn[2];
12041dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      if (epartIsReg(modrm)) {
12042dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( eV, getXMMReg( eregOfRM(modrm)) );
12043dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12044dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                   nameXMMReg(gregOfRM(modrm)));
12045dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 2+1;
12046dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      } else {
12047dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
12048dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12049dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("h%spd %s,%s\n", str, dis_buf,
12050dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                              nameXMMReg(gregOfRM(modrm)));
12051dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 2+alen;
12052dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      }
12053dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
12054dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( gV, getXMMReg(gregOfRM(modrm)) );
12055dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
12056dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
12057dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
12058dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
12059dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
12060dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
12061dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( leftV,  binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
12062dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
12063dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
120649571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
12065dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      putXMMReg( gregOfRM(modrm),
120669571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                 triop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
120679571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                       mkexpr(rm), mkexpr(leftV), mkexpr(rightV) ) );
12068dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      goto decode_success;
12069dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   }
12070dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
12071dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
12072dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xF0) {
12073dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      modrm = getIByte(delta+3);
12074dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      if (epartIsReg(modrm)) {
12075dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         goto decode_failure;
12076dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      } else {
12077dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12078dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         putXMMReg( gregOfRM(modrm),
12079dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                    loadLE(Ity_V128, mkexpr(addr)) );
12080dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("lddqu %s,%s\n", dis_buf,
12081dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                              nameXMMReg(gregOfRM(modrm)));
12082dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 3+alen;
12083dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      }
12084dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      goto decode_success;
12085dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   }
12086dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
1208790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* ---------------------------------------------------- */
1208890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* --- end of the SSE3 decoder.                     --- */
12089c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* ---------------------------------------------------- */
12090c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
12091150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* ---------------------------------------------------- */
12092150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* --- start of the SSSE3 decoder.                  --- */
12093150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* ---------------------------------------------------- */
12094150c9cddb753ad4dc38f43484144523174d38b02sewardj
12095150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
12096150c9cddb753ad4dc38f43484144523174d38b02sewardj      Unsigned Bytes (MMX) */
12097150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12098150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
12099150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV        = newTemp(Ity_I64);
12100150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV        = newTemp(Ity_I64);
12101150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sVoddsSX  = newTemp(Ity_I64);
12102150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sVevensSX = newTemp(Ity_I64);
12103150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dVoddsZX  = newTemp(Ity_I64);
12104150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dVevensZX = newTemp(Ity_I64);
12105150c9cddb753ad4dc38f43484144523174d38b02sewardj
12106150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12107150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12108150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
12109150c9cddb753ad4dc38f43484144523174d38b02sewardj
12110150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12111150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12112150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12113150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmaddubsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12114150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameMMXReg(gregOfRM(modrm)));
12115150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12116150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12117150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12118150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12119150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmaddubsw %s,%s\n", dis_buf,
12120150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameMMXReg(gregOfRM(modrm)));
12121150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12122150c9cddb753ad4dc38f43484144523174d38b02sewardj
12123150c9cddb753ad4dc38f43484144523174d38b02sewardj      /* compute dV unsigned x sV signed */
12124150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sVoddsSX,
12125150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_SarN16x4, mkexpr(sV), mkU8(8)) );
12126150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sVevensSX,
12127150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_SarN16x4,
12128150c9cddb753ad4dc38f43484144523174d38b02sewardj                    binop(Iop_ShlN16x4, mkexpr(sV), mkU8(8)),
12129150c9cddb753ad4dc38f43484144523174d38b02sewardj                    mkU8(8)) );
12130150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dVoddsZX,
12131150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_ShrN16x4, mkexpr(dV), mkU8(8)) );
12132150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dVevensZX,
12133150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_ShrN16x4,
12134150c9cddb753ad4dc38f43484144523174d38b02sewardj                    binop(Iop_ShlN16x4, mkexpr(dV), mkU8(8)),
12135150c9cddb753ad4dc38f43484144523174d38b02sewardj                    mkU8(8)) );
12136150c9cddb753ad4dc38f43484144523174d38b02sewardj
12137150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg(
12138150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12139150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_QAdd16Sx4,
12140150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_Mul16x4, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
12141150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_Mul16x4, mkexpr(sVevensSX), mkexpr(dVevensZX))
12142150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12143150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12144150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12145150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12146150c9cddb753ad4dc38f43484144523174d38b02sewardj
12147150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
12148150c9cddb753ad4dc38f43484144523174d38b02sewardj      Unsigned Bytes (XMM) */
12149150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12150150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
12151150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV        = newTemp(Ity_V128);
12152150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV        = newTemp(Ity_V128);
12153150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sVoddsSX  = newTemp(Ity_V128);
12154150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sVevensSX = newTemp(Ity_V128);
12155150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dVoddsZX  = newTemp(Ity_V128);
12156150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dVevensZX = newTemp(Ity_V128);
12157150c9cddb753ad4dc38f43484144523174d38b02sewardj
12158150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12159150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
12160150c9cddb753ad4dc38f43484144523174d38b02sewardj
12161150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12162150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
12163150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12164150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmaddubsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12165150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameXMMReg(gregOfRM(modrm)));
12166150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12167150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12168150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12169150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12170150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12171150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmaddubsw %s,%s\n", dis_buf,
12172150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameXMMReg(gregOfRM(modrm)));
12173150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12174150c9cddb753ad4dc38f43484144523174d38b02sewardj
12175150c9cddb753ad4dc38f43484144523174d38b02sewardj      /* compute dV unsigned x sV signed */
12176150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sVoddsSX,
12177150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_SarN16x8, mkexpr(sV), mkU8(8)) );
12178150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sVevensSX,
12179150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_SarN16x8,
12180150c9cddb753ad4dc38f43484144523174d38b02sewardj                    binop(Iop_ShlN16x8, mkexpr(sV), mkU8(8)),
12181150c9cddb753ad4dc38f43484144523174d38b02sewardj                    mkU8(8)) );
12182150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dVoddsZX,
12183150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_ShrN16x8, mkexpr(dV), mkU8(8)) );
12184150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dVevensZX,
12185150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_ShrN16x8,
12186150c9cddb753ad4dc38f43484144523174d38b02sewardj                    binop(Iop_ShlN16x8, mkexpr(dV), mkU8(8)),
12187150c9cddb753ad4dc38f43484144523174d38b02sewardj                    mkU8(8)) );
12188150c9cddb753ad4dc38f43484144523174d38b02sewardj
12189150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12190150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12191150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_QAdd16Sx8,
12192150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_Mul16x8, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
12193150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_Mul16x8, mkexpr(sVevensSX), mkexpr(dVevensZX))
12194150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12195150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12196150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12197150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12198150c9cddb753ad4dc38f43484144523174d38b02sewardj
12199150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* ***--- these are MMX class insns introduced in SSSE3 ---*** */
12200150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 03 = PHADDSW -- 16x4 signed qadd across from E (mem or
12201150c9cddb753ad4dc38f43484144523174d38b02sewardj      mmx) and G to G (mmx). */
12202150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 07 = PHSUBSW -- 16x4 signed qsub across from E (mem or
12203150c9cddb753ad4dc38f43484144523174d38b02sewardj      mmx) and G to G (mmx). */
12204150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 01 = PHADDW -- 16x4 add across from E (mem or mmx) and G
12205150c9cddb753ad4dc38f43484144523174d38b02sewardj      to G (mmx). */
12206150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 05 = PHSUBW -- 16x4 sub across from E (mem or mmx) and G
12207150c9cddb753ad4dc38f43484144523174d38b02sewardj      to G (mmx). */
12208150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 02 = PHADDD -- 32x2 add across from E (mem or mmx) and G
12209150c9cddb753ad4dc38f43484144523174d38b02sewardj      to G (mmx). */
12210150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 06 = PHSUBD -- 32x2 sub across from E (mem or mmx) and G
12211150c9cddb753ad4dc38f43484144523174d38b02sewardj      to G (mmx). */
12212150c9cddb753ad4dc38f43484144523174d38b02sewardj
12213150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12214150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38
12215150c9cddb753ad4dc38f43484144523174d38b02sewardj       && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
12216150c9cddb753ad4dc38f43484144523174d38b02sewardj           || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
1221755085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = "???";
12218150c9cddb753ad4dc38f43484144523174d38b02sewardj      IROp   opV64  = Iop_INVALID;
12219150c9cddb753ad4dc38f43484144523174d38b02sewardj      IROp   opCatO = Iop_CatOddLanes16x4;
12220150c9cddb753ad4dc38f43484144523174d38b02sewardj      IROp   opCatE = Iop_CatEvenLanes16x4;
12221150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV     = newTemp(Ity_I64);
12222150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV     = newTemp(Ity_I64);
12223150c9cddb753ad4dc38f43484144523174d38b02sewardj
12224150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12225150c9cddb753ad4dc38f43484144523174d38b02sewardj
12226150c9cddb753ad4dc38f43484144523174d38b02sewardj      switch (insn[2]) {
12227150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
12228150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
12229150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x01: opV64 = Iop_Add16x4;   str = "addw";  break;
12230150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x05: opV64 = Iop_Sub16x4;   str = "subw";  break;
12231150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x02: opV64 = Iop_Add32x2;   str = "addd";  break;
12232150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x06: opV64 = Iop_Sub32x2;   str = "subd";  break;
12233150c9cddb753ad4dc38f43484144523174d38b02sewardj         default: vassert(0);
12234150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12235150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (insn[2] == 0x02 || insn[2] == 0x06) {
12236150c9cddb753ad4dc38f43484144523174d38b02sewardj         opCatO = Iop_InterleaveHI32x2;
12237150c9cddb753ad4dc38f43484144523174d38b02sewardj         opCatE = Iop_InterleaveLO32x2;
12238150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12239150c9cddb753ad4dc38f43484144523174d38b02sewardj
12240150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12241150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
12242150c9cddb753ad4dc38f43484144523174d38b02sewardj
12243150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12244150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12245150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12246150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("ph%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12247150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameMMXReg(gregOfRM(modrm)));
12248150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12249150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12250150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12251150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12252150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("ph%s %s,%s\n", str, dis_buf,
12253150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameMMXReg(gregOfRM(modrm)));
12254150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12255150c9cddb753ad4dc38f43484144523174d38b02sewardj
12256150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg(
12257150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12258150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(opV64,
12259150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(opCatE,mkexpr(sV),mkexpr(dV)),
12260150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(opCatO,mkexpr(sV),mkexpr(dV))
12261150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12262150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12263150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12264150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12265150c9cddb753ad4dc38f43484144523174d38b02sewardj
12266150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 03 = PHADDSW -- 16x8 signed qadd across from E (mem or
12267150c9cddb753ad4dc38f43484144523174d38b02sewardj      xmm) and G to G (xmm). */
12268150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 07 = PHSUBSW -- 16x8 signed qsub across from E (mem or
12269150c9cddb753ad4dc38f43484144523174d38b02sewardj      xmm) and G to G (xmm). */
12270150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 01 = PHADDW -- 16x8 add across from E (mem or xmm) and
12271150c9cddb753ad4dc38f43484144523174d38b02sewardj      G to G (xmm). */
12272150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 05 = PHSUBW -- 16x8 sub across from E (mem or xmm) and
12273150c9cddb753ad4dc38f43484144523174d38b02sewardj      G to G (xmm). */
12274150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 02 = PHADDD -- 32x4 add across from E (mem or xmm) and
12275150c9cddb753ad4dc38f43484144523174d38b02sewardj      G to G (xmm). */
12276150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 06 = PHSUBD -- 32x4 sub across from E (mem or xmm) and
12277150c9cddb753ad4dc38f43484144523174d38b02sewardj      G to G (xmm). */
12278150c9cddb753ad4dc38f43484144523174d38b02sewardj
12279150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12280150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38
12281150c9cddb753ad4dc38f43484144523174d38b02sewardj       && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
12282150c9cddb753ad4dc38f43484144523174d38b02sewardj           || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
1228355085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = "???";
12284150c9cddb753ad4dc38f43484144523174d38b02sewardj      IROp   opV64  = Iop_INVALID;
12285150c9cddb753ad4dc38f43484144523174d38b02sewardj      IROp   opCatO = Iop_CatOddLanes16x4;
12286150c9cddb753ad4dc38f43484144523174d38b02sewardj      IROp   opCatE = Iop_CatEvenLanes16x4;
12287150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV     = newTemp(Ity_V128);
12288150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV     = newTemp(Ity_V128);
12289150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sHi    = newTemp(Ity_I64);
12290150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sLo    = newTemp(Ity_I64);
12291150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dHi    = newTemp(Ity_I64);
12292150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dLo    = newTemp(Ity_I64);
12293150c9cddb753ad4dc38f43484144523174d38b02sewardj
12294150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12295150c9cddb753ad4dc38f43484144523174d38b02sewardj
12296150c9cddb753ad4dc38f43484144523174d38b02sewardj      switch (insn[2]) {
12297150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
12298150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
12299150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x01: opV64 = Iop_Add16x4;   str = "addw";  break;
12300150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x05: opV64 = Iop_Sub16x4;   str = "subw";  break;
12301150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x02: opV64 = Iop_Add32x2;   str = "addd";  break;
12302150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x06: opV64 = Iop_Sub32x2;   str = "subd";  break;
12303150c9cddb753ad4dc38f43484144523174d38b02sewardj         default: vassert(0);
12304150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12305150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (insn[2] == 0x02 || insn[2] == 0x06) {
12306150c9cddb753ad4dc38f43484144523174d38b02sewardj         opCatO = Iop_InterleaveHI32x2;
12307150c9cddb753ad4dc38f43484144523174d38b02sewardj         opCatE = Iop_InterleaveLO32x2;
12308150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12309150c9cddb753ad4dc38f43484144523174d38b02sewardj
12310150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
12311150c9cddb753ad4dc38f43484144523174d38b02sewardj
12312150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12313150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg( eregOfRM(modrm)) );
12314150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("ph%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12315150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameXMMReg(gregOfRM(modrm)));
12316150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12317150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12318150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12319150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12320150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12321150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("ph%s %s,%s\n", str, dis_buf,
12322150c9cddb753ad4dc38f43484144523174d38b02sewardj                             nameXMMReg(gregOfRM(modrm)));
12323150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12324150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12325150c9cddb753ad4dc38f43484144523174d38b02sewardj
12326150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12327150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12328150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12329150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12330150c9cddb753ad4dc38f43484144523174d38b02sewardj
12331150c9cddb753ad4dc38f43484144523174d38b02sewardj      /* This isn't a particularly efficient way to compute the
12332150c9cddb753ad4dc38f43484144523174d38b02sewardj         result, but at least it avoids a proliferation of IROps,
12333150c9cddb753ad4dc38f43484144523174d38b02sewardj         hence avoids complication all the backends. */
12334150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12335150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12336150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_64HLtoV128,
12337150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(opV64,
12338150c9cddb753ad4dc38f43484144523174d38b02sewardj                     binop(opCatE,mkexpr(sHi),mkexpr(sLo)),
12339150c9cddb753ad4dc38f43484144523174d38b02sewardj                     binop(opCatO,mkexpr(sHi),mkexpr(sLo))
12340150c9cddb753ad4dc38f43484144523174d38b02sewardj               ),
12341150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(opV64,
12342150c9cddb753ad4dc38f43484144523174d38b02sewardj                     binop(opCatE,mkexpr(dHi),mkexpr(dLo)),
12343150c9cddb753ad4dc38f43484144523174d38b02sewardj                     binop(opCatO,mkexpr(dHi),mkexpr(dLo))
12344150c9cddb753ad4dc38f43484144523174d38b02sewardj               )
12345150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12346150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12347150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12348150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12349150c9cddb753ad4dc38f43484144523174d38b02sewardj
12350150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and Scale
12351150c9cddb753ad4dc38f43484144523174d38b02sewardj      (MMX) */
12352150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12353150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12354150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV = newTemp(Ity_I64);
12355150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV = newTemp(Ity_I64);
12356150c9cddb753ad4dc38f43484144523174d38b02sewardj
12357150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12358150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12359150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
12360150c9cddb753ad4dc38f43484144523174d38b02sewardj
12361150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12362150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12363150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12364150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmulhrsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12365150c9cddb753ad4dc38f43484144523174d38b02sewardj                                 nameMMXReg(gregOfRM(modrm)));
12366150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12367150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12368150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12369150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12370150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmulhrsw %s,%s\n", dis_buf,
12371150c9cddb753ad4dc38f43484144523174d38b02sewardj                                 nameMMXReg(gregOfRM(modrm)));
12372150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12373150c9cddb753ad4dc38f43484144523174d38b02sewardj
12374150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg(
12375150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12376150c9cddb753ad4dc38f43484144523174d38b02sewardj         dis_PMULHRSW_helper( mkexpr(sV), mkexpr(dV) )
12377150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12378150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12379150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12380150c9cddb753ad4dc38f43484144523174d38b02sewardj
12381150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and
12382150c9cddb753ad4dc38f43484144523174d38b02sewardj      Scale (XMM) */
12383150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12384150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12385150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV  = newTemp(Ity_V128);
12386150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV  = newTemp(Ity_V128);
12387150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sHi = newTemp(Ity_I64);
12388150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sLo = newTemp(Ity_I64);
12389150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dHi = newTemp(Ity_I64);
12390150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dLo = newTemp(Ity_I64);
12391150c9cddb753ad4dc38f43484144523174d38b02sewardj
12392150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12393150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
12394150c9cddb753ad4dc38f43484144523174d38b02sewardj
12395150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12396150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
12397150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12398150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmulhrsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12399150c9cddb753ad4dc38f43484144523174d38b02sewardj                                 nameXMMReg(gregOfRM(modrm)));
12400150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12401150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12402150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12403150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12404150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12405150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmulhrsw %s,%s\n", dis_buf,
12406150c9cddb753ad4dc38f43484144523174d38b02sewardj                                 nameXMMReg(gregOfRM(modrm)));
12407150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12408150c9cddb753ad4dc38f43484144523174d38b02sewardj
12409150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12410150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12411150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12412150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12413150c9cddb753ad4dc38f43484144523174d38b02sewardj
12414150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12415150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12416150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_64HLtoV128,
12417150c9cddb753ad4dc38f43484144523174d38b02sewardj               dis_PMULHRSW_helper( mkexpr(sHi), mkexpr(dHi) ),
12418150c9cddb753ad4dc38f43484144523174d38b02sewardj               dis_PMULHRSW_helper( mkexpr(sLo), mkexpr(dLo) )
12419150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12420150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12421150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12422150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12423150c9cddb753ad4dc38f43484144523174d38b02sewardj
12424150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 08 = PSIGNB -- Packed Sign 8x8  (MMX) */
12425150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 09 = PSIGNW -- Packed Sign 16x4 (MMX) */
12426150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 09 = PSIGND -- Packed Sign 32x2 (MMX) */
12427150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12428150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38
12429150c9cddb753ad4dc38f43484144523174d38b02sewardj       && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12430150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV      = newTemp(Ity_I64);
12431150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV      = newTemp(Ity_I64);
1243255085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = "???";
12433150c9cddb753ad4dc38f43484144523174d38b02sewardj      Int    laneszB = 0;
12434150c9cddb753ad4dc38f43484144523174d38b02sewardj
12435150c9cddb753ad4dc38f43484144523174d38b02sewardj      switch (insn[2]) {
12436150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x08: laneszB = 1; str = "b"; break;
12437150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x09: laneszB = 2; str = "w"; break;
12438150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x0A: laneszB = 4; str = "d"; break;
12439150c9cddb753ad4dc38f43484144523174d38b02sewardj         default: vassert(0);
12440150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12441150c9cddb753ad4dc38f43484144523174d38b02sewardj
12442150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12443150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12444150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
12445150c9cddb753ad4dc38f43484144523174d38b02sewardj
12446150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12447150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12448150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12449150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("psign%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12450150c9cddb753ad4dc38f43484144523174d38b02sewardj                                     nameMMXReg(gregOfRM(modrm)));
12451150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12452150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12453150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12454150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12455150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("psign%s %s,%s\n", str, dis_buf,
12456150c9cddb753ad4dc38f43484144523174d38b02sewardj                                     nameMMXReg(gregOfRM(modrm)));
12457150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12458150c9cddb753ad4dc38f43484144523174d38b02sewardj
12459150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg(
12460150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12461150c9cddb753ad4dc38f43484144523174d38b02sewardj         dis_PSIGN_helper( mkexpr(sV), mkexpr(dV), laneszB )
12462150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12463150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12464150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12465150c9cddb753ad4dc38f43484144523174d38b02sewardj
12466150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 08 = PSIGNB -- Packed Sign 8x16 (XMM) */
12467150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 09 = PSIGNW -- Packed Sign 16x8 (XMM) */
12468150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 09 = PSIGND -- Packed Sign 32x4 (XMM) */
12469150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12470150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38
12471150c9cddb753ad4dc38f43484144523174d38b02sewardj       && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12472150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV      = newTemp(Ity_V128);
12473150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV      = newTemp(Ity_V128);
12474150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sHi     = newTemp(Ity_I64);
12475150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sLo     = newTemp(Ity_I64);
12476150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dHi     = newTemp(Ity_I64);
12477150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dLo     = newTemp(Ity_I64);
1247855085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = "???";
12479150c9cddb753ad4dc38f43484144523174d38b02sewardj      Int    laneszB = 0;
12480150c9cddb753ad4dc38f43484144523174d38b02sewardj
12481150c9cddb753ad4dc38f43484144523174d38b02sewardj      switch (insn[2]) {
12482150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x08: laneszB = 1; str = "b"; break;
12483150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x09: laneszB = 2; str = "w"; break;
12484150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x0A: laneszB = 4; str = "d"; break;
12485150c9cddb753ad4dc38f43484144523174d38b02sewardj         default: vassert(0);
12486150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12487150c9cddb753ad4dc38f43484144523174d38b02sewardj
12488150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12489150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
12490150c9cddb753ad4dc38f43484144523174d38b02sewardj
12491150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12492150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
12493150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12494150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("psign%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12495150c9cddb753ad4dc38f43484144523174d38b02sewardj                                     nameXMMReg(gregOfRM(modrm)));
12496150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12497150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12498150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12499150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12500150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12501150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("psign%s %s,%s\n", str, dis_buf,
12502150c9cddb753ad4dc38f43484144523174d38b02sewardj                                     nameXMMReg(gregOfRM(modrm)));
12503150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12504150c9cddb753ad4dc38f43484144523174d38b02sewardj
12505150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12506150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12507150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12508150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12509150c9cddb753ad4dc38f43484144523174d38b02sewardj
12510150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12511150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12512150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_64HLtoV128,
12513150c9cddb753ad4dc38f43484144523174d38b02sewardj               dis_PSIGN_helper( mkexpr(sHi), mkexpr(dHi), laneszB ),
12514150c9cddb753ad4dc38f43484144523174d38b02sewardj               dis_PSIGN_helper( mkexpr(sLo), mkexpr(dLo), laneszB )
12515150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12516150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12517150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12518150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12519150c9cddb753ad4dc38f43484144523174d38b02sewardj
12520150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 1C = PABSB -- Packed Absolute Value 8x8  (MMX) */
12521150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 1D = PABSW -- Packed Absolute Value 16x4 (MMX) */
12522150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 1E = PABSD -- Packed Absolute Value 32x2 (MMX) */
12523150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12524150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38
12525150c9cddb753ad4dc38f43484144523174d38b02sewardj       && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12526150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV      = newTemp(Ity_I64);
1252755085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = "???";
12528150c9cddb753ad4dc38f43484144523174d38b02sewardj      Int    laneszB = 0;
12529150c9cddb753ad4dc38f43484144523174d38b02sewardj
12530150c9cddb753ad4dc38f43484144523174d38b02sewardj      switch (insn[2]) {
12531150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x1C: laneszB = 1; str = "b"; break;
12532150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x1D: laneszB = 2; str = "w"; break;
12533150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x1E: laneszB = 4; str = "d"; break;
12534150c9cddb753ad4dc38f43484144523174d38b02sewardj         default: vassert(0);
12535150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12536150c9cddb753ad4dc38f43484144523174d38b02sewardj
12537150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12538150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12539150c9cddb753ad4dc38f43484144523174d38b02sewardj
12540150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12541150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12542150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12543150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pabs%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12544150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameMMXReg(gregOfRM(modrm)));
12545150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12546150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12547150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12548150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12549150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pabs%s %s,%s\n", str, dis_buf,
12550150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameMMXReg(gregOfRM(modrm)));
12551150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12552150c9cddb753ad4dc38f43484144523174d38b02sewardj
12553150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg(
12554150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12555150c9cddb753ad4dc38f43484144523174d38b02sewardj         dis_PABS_helper( mkexpr(sV), laneszB )
12556150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12557150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12558150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12559150c9cddb753ad4dc38f43484144523174d38b02sewardj
12560150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 1C = PABSB -- Packed Absolute Value 8x16 (XMM) */
12561150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 1D = PABSW -- Packed Absolute Value 16x8 (XMM) */
12562150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 1E = PABSD -- Packed Absolute Value 32x4 (XMM) */
12563150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12564150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38
12565150c9cddb753ad4dc38f43484144523174d38b02sewardj       && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12566150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV      = newTemp(Ity_V128);
12567150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sHi     = newTemp(Ity_I64);
12568150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sLo     = newTemp(Ity_I64);
1256955085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = "???";
12570150c9cddb753ad4dc38f43484144523174d38b02sewardj      Int    laneszB = 0;
12571150c9cddb753ad4dc38f43484144523174d38b02sewardj
12572150c9cddb753ad4dc38f43484144523174d38b02sewardj      switch (insn[2]) {
12573150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x1C: laneszB = 1; str = "b"; break;
12574150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x1D: laneszB = 2; str = "w"; break;
12575150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x1E: laneszB = 4; str = "d"; break;
12576150c9cddb753ad4dc38f43484144523174d38b02sewardj         default: vassert(0);
12577150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12578150c9cddb753ad4dc38f43484144523174d38b02sewardj
12579150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12580150c9cddb753ad4dc38f43484144523174d38b02sewardj
12581150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12582150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
12583150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12584150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pabs%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12585150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameXMMReg(gregOfRM(modrm)));
12586150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12587150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12588150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12589150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12590150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12591150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pabs%s %s,%s\n", str, dis_buf,
12592150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameXMMReg(gregOfRM(modrm)));
12593150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12594150c9cddb753ad4dc38f43484144523174d38b02sewardj
12595150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12596150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12597150c9cddb753ad4dc38f43484144523174d38b02sewardj
12598150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12599150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12600150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_64HLtoV128,
12601150c9cddb753ad4dc38f43484144523174d38b02sewardj               dis_PABS_helper( mkexpr(sHi), laneszB ),
12602150c9cddb753ad4dc38f43484144523174d38b02sewardj               dis_PABS_helper( mkexpr(sLo), laneszB )
12603150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12604150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12605150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12606150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12607150c9cddb753ad4dc38f43484144523174d38b02sewardj
12608150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 3A 0F = PALIGNR -- Packed Align Right (MMX) */
12609150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12610150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12611150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV  = newTemp(Ity_I64);
12612150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV  = newTemp(Ity_I64);
12613150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp res = newTemp(Ity_I64);
12614150c9cddb753ad4dc38f43484144523174d38b02sewardj
12615150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12616150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12617150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
12618150c9cddb753ad4dc38f43484144523174d38b02sewardj
12619150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12620150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12621150c9cddb753ad4dc38f43484144523174d38b02sewardj         d32 = (UInt)insn[3+1];
12622150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1+1;
12623b173774421d015736c2316b5e6e998e7de545a5cflorian         DIP("palignr $%u,%s,%s\n",  d32,
12624150c9cddb753ad4dc38f43484144523174d38b02sewardj                                     nameMMXReg(eregOfRM(modrm)),
12625150c9cddb753ad4dc38f43484144523174d38b02sewardj                                     nameMMXReg(gregOfRM(modrm)));
12626150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12627150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12628150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12629150c9cddb753ad4dc38f43484144523174d38b02sewardj         d32 = (UInt)insn[3+alen];
12630150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen+1;
12631b173774421d015736c2316b5e6e998e7de545a5cflorian         DIP("palignr $%u%s,%s\n", d32,
12632150c9cddb753ad4dc38f43484144523174d38b02sewardj                                   dis_buf,
12633150c9cddb753ad4dc38f43484144523174d38b02sewardj                                   nameMMXReg(gregOfRM(modrm)));
12634150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12635150c9cddb753ad4dc38f43484144523174d38b02sewardj
12636150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (d32 == 0) {
12637150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( res, mkexpr(sV) );
12638150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12639150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 1 && d32 <= 7) {
12640150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign(res,
12641150c9cddb753ad4dc38f43484144523174d38b02sewardj                binop(Iop_Or64,
12642150c9cddb753ad4dc38f43484144523174d38b02sewardj                      binop(Iop_Shr64, mkexpr(sV), mkU8(8*d32)),
12643150c9cddb753ad4dc38f43484144523174d38b02sewardj                      binop(Iop_Shl64, mkexpr(dV), mkU8(8*(8-d32))
12644150c9cddb753ad4dc38f43484144523174d38b02sewardj                     )));
12645150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12646150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 == 8) {
12647150c9cddb753ad4dc38f43484144523174d38b02sewardj        assign( res, mkexpr(dV) );
12648150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12649150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 9 && d32 <= 15) {
12650150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( res, binop(Iop_Shr64, mkexpr(dV), mkU8(8*(d32-8))) );
12651150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12652150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 16 && d32 <= 255) {
12653150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( res, mkU64(0) );
12654150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12655150c9cddb753ad4dc38f43484144523174d38b02sewardj      else
12656150c9cddb753ad4dc38f43484144523174d38b02sewardj         vassert(0);
12657150c9cddb753ad4dc38f43484144523174d38b02sewardj
12658150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg( gregOfRM(modrm), mkexpr(res) );
12659150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12660150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12661150c9cddb753ad4dc38f43484144523174d38b02sewardj
12662150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 3A 0F = PALIGNR -- Packed Align Right (XMM) */
12663150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12664150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12665150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV  = newTemp(Ity_V128);
12666150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV  = newTemp(Ity_V128);
12667150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sHi = newTemp(Ity_I64);
12668150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sLo = newTemp(Ity_I64);
12669150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dHi = newTemp(Ity_I64);
12670150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dLo = newTemp(Ity_I64);
12671150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp rHi = newTemp(Ity_I64);
12672150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp rLo = newTemp(Ity_I64);
12673150c9cddb753ad4dc38f43484144523174d38b02sewardj
12674150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12675150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
12676150c9cddb753ad4dc38f43484144523174d38b02sewardj
12677150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12678150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
12679150c9cddb753ad4dc38f43484144523174d38b02sewardj         d32 = (UInt)insn[3+1];
12680150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1+1;
12681b173774421d015736c2316b5e6e998e7de545a5cflorian         DIP("palignr $%u,%s,%s\n", d32,
12682150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameXMMReg(eregOfRM(modrm)),
12683150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameXMMReg(gregOfRM(modrm)));
12684150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12685150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12686150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12687150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12688150c9cddb753ad4dc38f43484144523174d38b02sewardj         d32 = (UInt)insn[3+alen];
12689150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen+1;
12690b173774421d015736c2316b5e6e998e7de545a5cflorian         DIP("palignr $%u,%s,%s\n", d32,
12691150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    dis_buf,
12692150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameXMMReg(gregOfRM(modrm)));
12693150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12694150c9cddb753ad4dc38f43484144523174d38b02sewardj
12695150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12696150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12697150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12698150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12699150c9cddb753ad4dc38f43484144523174d38b02sewardj
12700150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (d32 == 0) {
12701150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, mkexpr(sHi) );
12702150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, mkexpr(sLo) );
12703150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12704150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 1 && d32 <= 7) {
12705150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, dis_PALIGNR_XMM_helper(dLo, sHi, d32) );
12706150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, dis_PALIGNR_XMM_helper(sHi, sLo, d32) );
12707150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12708150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 == 8) {
12709150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, mkexpr(dLo) );
12710150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, mkexpr(sHi) );
12711150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12712150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 9 && d32 <= 15) {
12713150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, dis_PALIGNR_XMM_helper(dHi, dLo, d32-8) );
12714150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, dis_PALIGNR_XMM_helper(dLo, sHi, d32-8) );
12715150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12716150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 == 16) {
12717150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, mkexpr(dHi) );
12718150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, mkexpr(dLo) );
12719150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12720150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 17 && d32 <= 23) {
12721150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-16))) );
12722150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, dis_PALIGNR_XMM_helper(dHi, dLo, d32-16) );
12723150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12724150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 == 24) {
12725150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, mkU64(0) );
12726150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, mkexpr(dHi) );
12727150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12728150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 25 && d32 <= 31) {
12729150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, mkU64(0) );
12730150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-24))) );
12731150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12732150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 32 && d32 <= 255) {
12733150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, mkU64(0) );
12734150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, mkU64(0) );
12735150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12736150c9cddb753ad4dc38f43484144523174d38b02sewardj      else
12737150c9cddb753ad4dc38f43484144523174d38b02sewardj         vassert(0);
12738150c9cddb753ad4dc38f43484144523174d38b02sewardj
12739150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12740150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12741150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12742150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12743150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12744150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12745150c9cddb753ad4dc38f43484144523174d38b02sewardj
12746150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x8 (MMX) */
12747150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12748150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12749150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV      = newTemp(Ity_I64);
12750150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV      = newTemp(Ity_I64);
12751150c9cddb753ad4dc38f43484144523174d38b02sewardj
12752150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12753150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12754150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
12755150c9cddb753ad4dc38f43484144523174d38b02sewardj
12756150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12757150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12758150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12759150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pshufb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12760150c9cddb753ad4dc38f43484144523174d38b02sewardj                               nameMMXReg(gregOfRM(modrm)));
12761150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12762150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12763150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12764150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12765150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pshufb %s,%s\n", dis_buf,
12766150c9cddb753ad4dc38f43484144523174d38b02sewardj                               nameMMXReg(gregOfRM(modrm)));
12767150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12768150c9cddb753ad4dc38f43484144523174d38b02sewardj
12769150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg(
12770150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12771150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(
12772150c9cddb753ad4dc38f43484144523174d38b02sewardj            Iop_And64,
12773150c9cddb753ad4dc38f43484144523174d38b02sewardj            /* permute the lanes */
12774150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(
12775150c9cddb753ad4dc38f43484144523174d38b02sewardj               Iop_Perm8x8,
12776150c9cddb753ad4dc38f43484144523174d38b02sewardj               mkexpr(dV),
12777150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_And64, mkexpr(sV), mkU64(0x0707070707070707ULL))
12778150c9cddb753ad4dc38f43484144523174d38b02sewardj            ),
12779150c9cddb753ad4dc38f43484144523174d38b02sewardj            /* mask off lanes which have (index & 0x80) == 0x80 */
12780150c9cddb753ad4dc38f43484144523174d38b02sewardj            unop(Iop_Not64, binop(Iop_SarN8x8, mkexpr(sV), mkU8(7)))
12781150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12782150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12783150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12784150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12785150c9cddb753ad4dc38f43484144523174d38b02sewardj
12786150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x16 (XMM) */
12787150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12788150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12789150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV         = newTemp(Ity_V128);
12790150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV         = newTemp(Ity_V128);
12791150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sHi        = newTemp(Ity_I64);
12792150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sLo        = newTemp(Ity_I64);
12793150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dHi        = newTemp(Ity_I64);
12794150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dLo        = newTemp(Ity_I64);
12795150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp rHi        = newTemp(Ity_I64);
12796150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp rLo        = newTemp(Ity_I64);
12797150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sevens     = newTemp(Ity_I64);
12798150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp mask0x80hi = newTemp(Ity_I64);
12799150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp mask0x80lo = newTemp(Ity_I64);
12800150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp maskBit3hi = newTemp(Ity_I64);
12801150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp maskBit3lo = newTemp(Ity_I64);
12802150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sAnd7hi    = newTemp(Ity_I64);
12803150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sAnd7lo    = newTemp(Ity_I64);
12804150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp permdHi    = newTemp(Ity_I64);
12805150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp permdLo    = newTemp(Ity_I64);
12806150c9cddb753ad4dc38f43484144523174d38b02sewardj
12807150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12808150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
12809150c9cddb753ad4dc38f43484144523174d38b02sewardj
12810150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12811150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
12812150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12813150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pshufb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12814150c9cddb753ad4dc38f43484144523174d38b02sewardj                               nameXMMReg(gregOfRM(modrm)));
12815150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12816150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12817150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12818150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12819150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12820150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pshufb %s,%s\n", dis_buf,
12821150c9cddb753ad4dc38f43484144523174d38b02sewardj                               nameXMMReg(gregOfRM(modrm)));
12822150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12823150c9cddb753ad4dc38f43484144523174d38b02sewardj
12824150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12825150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12826150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12827150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12828150c9cddb753ad4dc38f43484144523174d38b02sewardj
12829150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sevens, mkU64(0x0707070707070707ULL) );
12830150c9cddb753ad4dc38f43484144523174d38b02sewardj
12831150c9cddb753ad4dc38f43484144523174d38b02sewardj      /*
12832150c9cddb753ad4dc38f43484144523174d38b02sewardj      mask0x80hi = Not(SarN8x8(sHi,7))
12833150c9cddb753ad4dc38f43484144523174d38b02sewardj      maskBit3hi = SarN8x8(ShlN8x8(sHi,4),7)
12834150c9cddb753ad4dc38f43484144523174d38b02sewardj      sAnd7hi    = And(sHi,sevens)
12835150c9cddb753ad4dc38f43484144523174d38b02sewardj      permdHi    = Or( And(Perm8x8(dHi,sAnd7hi),maskBit3hi),
12836150c9cddb753ad4dc38f43484144523174d38b02sewardj                       And(Perm8x8(dLo,sAnd7hi),Not(maskBit3hi)) )
12837150c9cddb753ad4dc38f43484144523174d38b02sewardj      rHi        = And(permdHi,mask0x80hi)
12838150c9cddb753ad4dc38f43484144523174d38b02sewardj      */
12839150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(
12840150c9cddb753ad4dc38f43484144523174d38b02sewardj         mask0x80hi,
12841150c9cddb753ad4dc38f43484144523174d38b02sewardj         unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sHi),mkU8(7))));
12842150c9cddb753ad4dc38f43484144523174d38b02sewardj
12843150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(
12844150c9cddb753ad4dc38f43484144523174d38b02sewardj         maskBit3hi,
12845150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_SarN8x8,
12846150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_ShlN8x8,mkexpr(sHi),mkU8(4)),
12847150c9cddb753ad4dc38f43484144523174d38b02sewardj               mkU8(7)));
12848150c9cddb753ad4dc38f43484144523174d38b02sewardj
12849150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(sAnd7hi, binop(Iop_And64,mkexpr(sHi),mkexpr(sevens)));
12850150c9cddb753ad4dc38f43484144523174d38b02sewardj
12851150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(
12852150c9cddb753ad4dc38f43484144523174d38b02sewardj         permdHi,
12853150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(
12854150c9cddb753ad4dc38f43484144523174d38b02sewardj            Iop_Or64,
12855150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64,
12856150c9cddb753ad4dc38f43484144523174d38b02sewardj                  binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7hi)),
12857150c9cddb753ad4dc38f43484144523174d38b02sewardj                  mkexpr(maskBit3hi)),
12858150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64,
12859150c9cddb753ad4dc38f43484144523174d38b02sewardj                  binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7hi)),
12860150c9cddb753ad4dc38f43484144523174d38b02sewardj                  unop(Iop_Not64,mkexpr(maskBit3hi))) ));
12861150c9cddb753ad4dc38f43484144523174d38b02sewardj
12862150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(rHi, binop(Iop_And64,mkexpr(permdHi),mkexpr(mask0x80hi)) );
12863150c9cddb753ad4dc38f43484144523174d38b02sewardj
12864150c9cddb753ad4dc38f43484144523174d38b02sewardj      /* And the same for the lower half of the result.  What fun. */
12865150c9cddb753ad4dc38f43484144523174d38b02sewardj
12866150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(
12867150c9cddb753ad4dc38f43484144523174d38b02sewardj         mask0x80lo,
12868150c9cddb753ad4dc38f43484144523174d38b02sewardj         unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sLo),mkU8(7))));
12869150c9cddb753ad4dc38f43484144523174d38b02sewardj
12870150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(
12871150c9cddb753ad4dc38f43484144523174d38b02sewardj         maskBit3lo,
12872150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_SarN8x8,
12873150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_ShlN8x8,mkexpr(sLo),mkU8(4)),
12874150c9cddb753ad4dc38f43484144523174d38b02sewardj               mkU8(7)));
12875150c9cddb753ad4dc38f43484144523174d38b02sewardj
12876150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(sAnd7lo, binop(Iop_And64,mkexpr(sLo),mkexpr(sevens)));
12877150c9cddb753ad4dc38f43484144523174d38b02sewardj
12878150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(
12879150c9cddb753ad4dc38f43484144523174d38b02sewardj         permdLo,
12880150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(
12881150c9cddb753ad4dc38f43484144523174d38b02sewardj            Iop_Or64,
12882150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64,
12883150c9cddb753ad4dc38f43484144523174d38b02sewardj                  binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7lo)),
12884150c9cddb753ad4dc38f43484144523174d38b02sewardj                  mkexpr(maskBit3lo)),
12885150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64,
12886150c9cddb753ad4dc38f43484144523174d38b02sewardj                  binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7lo)),
12887150c9cddb753ad4dc38f43484144523174d38b02sewardj                  unop(Iop_Not64,mkexpr(maskBit3lo))) ));
12888150c9cddb753ad4dc38f43484144523174d38b02sewardj
12889150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(rLo, binop(Iop_And64,mkexpr(permdLo),mkexpr(mask0x80lo)) );
12890150c9cddb753ad4dc38f43484144523174d38b02sewardj
12891150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12892150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12893150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12894150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12895150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12896150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12897021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj
12898021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   /* 0F 38 F0 = MOVBE m16/32(E), r16/32(G) */
12899021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   /* 0F 38 F1 = MOVBE r16/32(G), m16/32(E) */
12900021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   if ((sz == 2 || sz == 4)
12901021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj       && insn[0] == 0x0F && insn[1] == 0x38
12902021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj       && (insn[2] == 0xF0 || insn[2] == 0xF1)
12903021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj       && !epartIsReg(insn[3])) {
12904021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj
12905021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      modrm = insn[3];
12906021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      addr = disAMode(&alen, sorb, delta + 3, dis_buf);
12907021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      delta += 3 + alen;
12908021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      ty = szToITy(sz);
12909021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      IRTemp src = newTemp(ty);
12910021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj
12911021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      if (insn[2] == 0xF0) { /* LOAD */
12912021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         assign(src, loadLE(ty, mkexpr(addr)));
12913021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         IRTemp dst = math_BSWAP(src, ty);
12914021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         putIReg(sz, gregOfRM(modrm), mkexpr(dst));
12915021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         DIP("movbe %s,%s\n", dis_buf, nameIReg(sz, gregOfRM(modrm)));
12916021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      } else { /* STORE */
12917021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         assign(src, getIReg(sz, gregOfRM(modrm)));
12918021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         IRTemp dst = math_BSWAP(src, ty);
12919021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         storeLE(mkexpr(addr), mkexpr(dst));
12920021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         DIP("movbe %s,%s\n", nameIReg(sz, gregOfRM(modrm)), dis_buf);
12921021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      }
12922021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      goto decode_success;
12923021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   }
12924150c9cddb753ad4dc38f43484144523174d38b02sewardj
12925150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* ---------------------------------------------------- */
12926150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* --- end of the SSSE3 decoder.                    --- */
12927150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* ---------------------------------------------------- */
12928150c9cddb753ad4dc38f43484144523174d38b02sewardj
12929b72716141cdc951a57490a5745fcb498039936a8sewardj   /* ---------------------------------------------------- */
12930b72716141cdc951a57490a5745fcb498039936a8sewardj   /* --- start of the SSE4 decoder                    --- */
12931b72716141cdc951a57490a5745fcb498039936a8sewardj   /* ---------------------------------------------------- */
12932b72716141cdc951a57490a5745fcb498039936a8sewardj
12933b72716141cdc951a57490a5745fcb498039936a8sewardj   /* 66 0F 3A 0B /r ib = ROUNDSD imm8, xmm2/m64, xmm1
12934b72716141cdc951a57490a5745fcb498039936a8sewardj      (Partial implementation only -- only deal with cases where
12935b72716141cdc951a57490a5745fcb498039936a8sewardj      the rounding mode is specified directly by the immediate byte.)
12936b72716141cdc951a57490a5745fcb498039936a8sewardj      66 0F 3A 0A /r ib = ROUNDSS imm8, xmm2/m32, xmm1
12937b72716141cdc951a57490a5745fcb498039936a8sewardj      (Limitations ditto)
12938b72716141cdc951a57490a5745fcb498039936a8sewardj   */
12939b72716141cdc951a57490a5745fcb498039936a8sewardj   if (sz == 2
12940b72716141cdc951a57490a5745fcb498039936a8sewardj       && insn[0] == 0x0F && insn[1] == 0x3A
12941e66a24794add1000a26cee1878b8d138bd4db7earhyskidd       && (insn[2] == 0x0B || insn[2] == 0x0A)) {
12942b72716141cdc951a57490a5745fcb498039936a8sewardj
12943b72716141cdc951a57490a5745fcb498039936a8sewardj      Bool   isD = insn[2] == 0x0B;
12944b72716141cdc951a57490a5745fcb498039936a8sewardj      IRTemp src = newTemp(isD ? Ity_F64 : Ity_F32);
12945b72716141cdc951a57490a5745fcb498039936a8sewardj      IRTemp res = newTemp(isD ? Ity_F64 : Ity_F32);
12946b72716141cdc951a57490a5745fcb498039936a8sewardj      Int    imm = 0;
12947b72716141cdc951a57490a5745fcb498039936a8sewardj
12948b72716141cdc951a57490a5745fcb498039936a8sewardj      modrm = insn[3];
12949b72716141cdc951a57490a5745fcb498039936a8sewardj
12950b72716141cdc951a57490a5745fcb498039936a8sewardj      if (epartIsReg(modrm)) {
12951b72716141cdc951a57490a5745fcb498039936a8sewardj         assign( src,
12952b72716141cdc951a57490a5745fcb498039936a8sewardj                 isD ? getXMMRegLane64F( eregOfRM(modrm), 0 )
12953b72716141cdc951a57490a5745fcb498039936a8sewardj                     : getXMMRegLane32F( eregOfRM(modrm), 0 ) );
12954b72716141cdc951a57490a5745fcb498039936a8sewardj         imm = insn[3+1];
12955b72716141cdc951a57490a5745fcb498039936a8sewardj         if (imm & ~3) goto decode_failure;
12956b72716141cdc951a57490a5745fcb498039936a8sewardj         delta += 3+1+1;
12957b72716141cdc951a57490a5745fcb498039936a8sewardj         DIP( "rounds%c $%d,%s,%s\n",
12958b72716141cdc951a57490a5745fcb498039936a8sewardj              isD ? 'd' : 's',
12959b72716141cdc951a57490a5745fcb498039936a8sewardj              imm, nameXMMReg( eregOfRM(modrm) ),
12960b72716141cdc951a57490a5745fcb498039936a8sewardj                   nameXMMReg( gregOfRM(modrm) ) );
12961b72716141cdc951a57490a5745fcb498039936a8sewardj      } else {
12962b72716141cdc951a57490a5745fcb498039936a8sewardj         addr = disAMode( &alen, sorb, delta+3, dis_buf );
12963b72716141cdc951a57490a5745fcb498039936a8sewardj         assign( src, loadLE( isD ? Ity_F64 : Ity_F32, mkexpr(addr) ));
12964b72716141cdc951a57490a5745fcb498039936a8sewardj         imm = insn[3+alen];
12965b72716141cdc951a57490a5745fcb498039936a8sewardj         if (imm & ~3) goto decode_failure;
12966b72716141cdc951a57490a5745fcb498039936a8sewardj         delta += 3+alen+1;
12967b72716141cdc951a57490a5745fcb498039936a8sewardj         DIP( "roundsd $%d,%s,%s\n",
12968b72716141cdc951a57490a5745fcb498039936a8sewardj              imm, dis_buf, nameXMMReg( gregOfRM(modrm) ) );
12969b72716141cdc951a57490a5745fcb498039936a8sewardj      }
12970b72716141cdc951a57490a5745fcb498039936a8sewardj
12971b72716141cdc951a57490a5745fcb498039936a8sewardj      /* (imm & 3) contains an Intel-encoded rounding mode.  Because
12972b72716141cdc951a57490a5745fcb498039936a8sewardj         that encoding is the same as the encoding for IRRoundingMode,
12973b72716141cdc951a57490a5745fcb498039936a8sewardj         we can use that value directly in the IR as a rounding
12974b72716141cdc951a57490a5745fcb498039936a8sewardj         mode. */
12975b72716141cdc951a57490a5745fcb498039936a8sewardj      assign(res, binop(isD ? Iop_RoundF64toInt : Iop_RoundF32toInt,
12976b72716141cdc951a57490a5745fcb498039936a8sewardj                  mkU32(imm & 3), mkexpr(src)) );
12977b72716141cdc951a57490a5745fcb498039936a8sewardj
12978b72716141cdc951a57490a5745fcb498039936a8sewardj      if (isD)
12979b72716141cdc951a57490a5745fcb498039936a8sewardj         putXMMRegLane64F( gregOfRM(modrm), 0, mkexpr(res) );
12980b72716141cdc951a57490a5745fcb498039936a8sewardj      else
12981b72716141cdc951a57490a5745fcb498039936a8sewardj         putXMMRegLane32F( gregOfRM(modrm), 0, mkexpr(res) );
12982b72716141cdc951a57490a5745fcb498039936a8sewardj
12983b72716141cdc951a57490a5745fcb498039936a8sewardj      goto decode_success;
12984b72716141cdc951a57490a5745fcb498039936a8sewardj   }
12985b72716141cdc951a57490a5745fcb498039936a8sewardj
12986536fbabcc3770f42bb7370efd75e8e30e9a841c8sewardj   /* F3 0F BD -- LZCNT (count leading zeroes.  An AMD extension,
12987536fbabcc3770f42bb7370efd75e8e30e9a841c8sewardj      which we can only decode if we're sure this is an AMD cpu that
12988536fbabcc3770f42bb7370efd75e8e30e9a841c8sewardj      supports LZCNT, since otherwise it's BSR, which behaves
12989536fbabcc3770f42bb7370efd75e8e30e9a841c8sewardj      differently. */
12990536fbabcc3770f42bb7370efd75e8e30e9a841c8sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xBD
12991536fbabcc3770f42bb7370efd75e8e30e9a841c8sewardj       && 0 != (archinfo->hwcaps & VEX_HWCAPS_X86_LZCNT)) {
129929a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      vassert(sz == 2 || sz == 4);
129939a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      /*IRType*/ ty  = szToITy(sz);
129949a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      IRTemp     src = newTemp(ty);
129959a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      modrm = insn[3];
129969a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      if (epartIsReg(modrm)) {
129979a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         assign(src, getIReg(sz, eregOfRM(modrm)));
129989a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         delta += 3+1;
129999a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         DIP("lzcnt%c %s, %s\n", nameISize(sz),
130009a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj             nameIReg(sz, eregOfRM(modrm)),
130019a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj             nameIReg(sz, gregOfRM(modrm)));
130029a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      } else {
130039a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         addr = disAMode( &alen, sorb, delta+3, dis_buf );
130049a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         assign(src, loadLE(ty, mkexpr(addr)));
130059a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         delta += 3+alen;
130069a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         DIP("lzcnt%c %s, %s\n", nameISize(sz), dis_buf,
130079a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj             nameIReg(sz, gregOfRM(modrm)));
130089a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      }
130099a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
130109a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      IRTemp res = gen_LZCNT(ty, src);
130119a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      putIReg(sz, gregOfRM(modrm), mkexpr(res));
130129a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
130139a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      // Update flags.  This is pretty lame .. perhaps can do better
130149a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      // if this turns out to be performance critical.
130159a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      // O S A P are cleared.  Z is set if RESULT == 0.
130169a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      // C is set if SRC is zero.
130179a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      IRTemp src32 = newTemp(Ity_I32);
130189a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      IRTemp res32 = newTemp(Ity_I32);
130199a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      assign(src32, widenUto32(mkexpr(src)));
130209a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      assign(res32, widenUto32(mkexpr(res)));
130219a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
130229a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      IRTemp oszacp = newTemp(Ity_I32);
130239a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      assign(
130249a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         oszacp,
130259a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         binop(Iop_Or32,
130269a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj               binop(Iop_Shl32,
130279a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                     unop(Iop_1Uto32,
130289a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                          binop(Iop_CmpEQ32, mkexpr(res32), mkU32(0))),
130299a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                     mkU8(X86G_CC_SHIFT_Z)),
130309a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj               binop(Iop_Shl32,
130319a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                     unop(Iop_1Uto32,
130329a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                          binop(Iop_CmpEQ32, mkexpr(src32), mkU32(0))),
130339a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                     mkU8(X86G_CC_SHIFT_C))
130349a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         )
130359a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      );
130369a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
130379a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
130389a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
130399a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
130409a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(oszacp) ));
130419a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
130429a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      goto decode_success;
130439a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   }
130449a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
13045b72716141cdc951a57490a5745fcb498039936a8sewardj   /* ---------------------------------------------------- */
13046b72716141cdc951a57490a5745fcb498039936a8sewardj   /* --- end of the SSE4 decoder                      --- */
13047b72716141cdc951a57490a5745fcb498039936a8sewardj   /* ---------------------------------------------------- */
13048b72716141cdc951a57490a5745fcb498039936a8sewardj
130499df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj   after_sse_decoders:
130509df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj
13051dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* ---------------------------------------------------- */
13052dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* --- deal with misc 0x67 pfxs (addr size override) -- */
13053dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* ---------------------------------------------------- */
13054dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj
13055dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* 67 E3 = JCXZ (for JECXZ see below) */
13056dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   if (insn[0] == 0x67 && insn[1] == 0xE3 && sz == 4) {
13057dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj      delta += 2;
13058dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13059dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj      delta ++;
13060dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj      stmt( IRStmt_Exit(
13061dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj               binop(Iop_CmpEQ16, getIReg(2,R_ECX), mkU16(0)),
13062dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj               Ijk_Boring,
13063c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj               IRConst_U32(d32),
13064c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj               OFFB_EIP
13065dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj            ));
13066dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj       DIP("jcxz 0x%x\n", d32);
13067dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj       goto decode_success;
13068dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   }
13069dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj
13070dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* ---------------------------------------------------- */
13071dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* --- start of the baseline insn decoder            -- */
13072dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* ---------------------------------------------------- */
13073dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj
13074c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* Get the primary opcode. */
13075c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   opc = getIByte(delta); delta++;
13076c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
13077c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* We get here if the current insn isn't SSE, or this CPU doesn't
13078c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      support SSE. */
13079c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
13080c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   switch (opc) {
13081c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
13082c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* ------------------------ Control flow --------------- */
13083940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
13084940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   case 0xC2: /* RET imm16 */
13085940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      d32 = getUDisp16(delta);
13086940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      delta += 2;
13087c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      dis_ret(&dres, d32);
13088b173774421d015736c2316b5e6e998e7de545a5cflorian      DIP("ret %u\n", d32);
13089940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
13090e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   case 0xC3: /* RET */
13091c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      dis_ret(&dres, 0);
13092e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      DIP("ret\n");
13093e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
130940e9a0f551e190b475150dcd6bc4500033eb05338sewardj
130950e9a0f551e190b475150dcd6bc4500033eb05338sewardj   case 0xCF: /* IRET */
130960e9a0f551e190b475150dcd6bc4500033eb05338sewardj      /* Note, this is an extremely kludgey and limited implementation
130970e9a0f551e190b475150dcd6bc4500033eb05338sewardj         of iret.  All it really does is:
130980e9a0f551e190b475150dcd6bc4500033eb05338sewardj            popl %EIP; popl %CS; popl %EFLAGS.
130990e9a0f551e190b475150dcd6bc4500033eb05338sewardj         %CS is set but ignored (as it is in (eg) popw %cs)". */
131000e9a0f551e190b475150dcd6bc4500033eb05338sewardj      t1 = newTemp(Ity_I32); /* ESP */
131010e9a0f551e190b475150dcd6bc4500033eb05338sewardj      t2 = newTemp(Ity_I32); /* new EIP */
131020e9a0f551e190b475150dcd6bc4500033eb05338sewardj      t3 = newTemp(Ity_I32); /* new CS */
131030e9a0f551e190b475150dcd6bc4500033eb05338sewardj      t4 = newTemp(Ity_I32); /* new EFLAGS */
131040e9a0f551e190b475150dcd6bc4500033eb05338sewardj      assign(t1, getIReg(4,R_ESP));
131050e9a0f551e190b475150dcd6bc4500033eb05338sewardj      assign(t2, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(0) )));
131060e9a0f551e190b475150dcd6bc4500033eb05338sewardj      assign(t3, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(4) )));
131070e9a0f551e190b475150dcd6bc4500033eb05338sewardj      assign(t4, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(8) )));
131080e9a0f551e190b475150dcd6bc4500033eb05338sewardj      /* Get stuff off stack */
131090e9a0f551e190b475150dcd6bc4500033eb05338sewardj      putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(12)));
131100e9a0f551e190b475150dcd6bc4500033eb05338sewardj      /* set %CS (which is ignored anyway) */
131110e9a0f551e190b475150dcd6bc4500033eb05338sewardj      putSReg( R_CS, unop(Iop_32to16, mkexpr(t3)) );
131120e9a0f551e190b475150dcd6bc4500033eb05338sewardj      /* set %EFLAGS */
131130e9a0f551e190b475150dcd6bc4500033eb05338sewardj      set_EFLAGS_from_value( t4, False/*!emit_AC_emwarn*/, 0/*unused*/ );
131140e9a0f551e190b475150dcd6bc4500033eb05338sewardj      /* goto new EIP value */
13115c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      jmp_treg(&dres, Ijk_Ret, t2);
13116c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      vassert(dres.whatNext == Dis_StopHere);
131170e9a0f551e190b475150dcd6bc4500033eb05338sewardj      DIP("iret (very kludgey)\n");
131180e9a0f551e190b475150dcd6bc4500033eb05338sewardj      break;
131190e9a0f551e190b475150dcd6bc4500033eb05338sewardj
13120d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0xE8: /* CALL J4 */
13121d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      d32 = getUDisp32(delta); delta += 4;
131229e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj      d32 += (guest_EIP_bbstart+delta);
13123ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj      /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
131249e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj      if (d32 == guest_EIP_bbstart+delta && getIByte(delta) >= 0x58
13125ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj                                         && getIByte(delta) <= 0x5F) {
13126d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         /* Specially treat the position-independent-code idiom
13127d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                 call X
13128d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj              X: popl %reg
13129d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            as
13130d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                 movl %eip, %reg.
13131d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            since this generates better code, but for no other reason. */
13132d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         Int archReg = getIByte(delta) - 0x58;
13133c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         /* vex_printf("-- fPIC thingy\n"); */
131349e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj         putIReg(4, archReg, mkU32(guest_EIP_bbstart+delta));
13135d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         delta++; /* Step over the POP */
13136d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
13137c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      } else {
13138d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         /* The normal sequence for a call. */
13139d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         t1 = newTemp(Ity_I32);
1314041f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj         assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
1314141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj         putIReg(4, R_ESP, mkexpr(t1));
131429e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj         storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
13143beac530a718fcc646bc61fe60a86f599df54e1d7florian         if (resteerOkFn( callback_opaque, (Addr32)d32 )) {
13144ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj            /* follow into the call target. */
13145984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            dres.whatNext   = Dis_ResteerU;
131460eaa35ff5569f09129073be27c2f827926f7010dflorian            dres.continueAt = (Addr32)d32;
13147ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj         } else {
13148c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_lit(&dres, Ijk_Call, d32);
13149c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres.whatNext == Dis_StopHere);
13150ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj         }
13151d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         DIP("call 0x%x\n",d32);
13152d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      }
13153d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      break;
13154d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
13155c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--    case 0xC8: /* ENTER */
13156c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       d32 = getUDisp16(eip); eip += 2;
13157c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       abyte = getIByte(delta); delta++;
13158c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
13159c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       vg_assert(sz == 4);
13160c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       vg_assert(abyte == 0);
13161c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
13162c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       t1 = newTemp(cb); t2 = newTemp(cb);
13163c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr2(cb, GET,   sz, ArchReg, R_EBP, TempReg, t1);
13164c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr2(cb, GET,    4, ArchReg, R_ESP, TempReg, t2);
13165c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr2(cb, SUB,    4, Literal, 0,     TempReg, t2);
13166c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uLiteral(cb, sz);
13167c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_ESP);
13168c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr2(cb, STORE,  4, TempReg, t1,    TempReg, t2);
13169c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_EBP);
13170c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       if (d32) {
13171c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, SUB,    4, Literal, 0,     TempReg, t2);
131725bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj//--          uLiteral(cb, d32);
131735bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj//--          uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_ESP);
13174c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       }
13175c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       DIP("enter 0x%x, 0x%x", d32, abyte);
13176c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       break;
13177c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
13178c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xC9: /* LEAVE */
13179c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      vassert(sz == 4);
13180c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13181c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      assign(t1, getIReg(4,R_EBP));
13182c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      /* First PUT ESP looks redundant, but need it because ESP must
13183c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         always be up-to-date for Memcheck to work... */
13184c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      putIReg(4, R_ESP, mkexpr(t1));
13185c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      assign(t2, loadLE(Ity_I32,mkexpr(t1)));
13186c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      putIReg(4, R_EBP, mkexpr(t2));
13187c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
13188c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      DIP("leave\n");
13189c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
13190c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
131918edc36b45e95a7ec9879a25b80390129f1d334c1sewardj   /* ---------------- Misc weird-ass insns --------------- */
131928edc36b45e95a7ec9879a25b80390129f1d334c1sewardj
131938edc36b45e95a7ec9879a25b80390129f1d334c1sewardj   case 0x27: /* DAA */
131948edc36b45e95a7ec9879a25b80390129f1d334c1sewardj   case 0x2F: /* DAS */
131958edc36b45e95a7ec9879a25b80390129f1d334c1sewardj   case 0x37: /* AAA */
131968edc36b45e95a7ec9879a25b80390129f1d334c1sewardj   case 0x3F: /* AAS */
131978edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      /* An ugly implementation for some ugly instructions.  Oh
131988edc36b45e95a7ec9879a25b80390129f1d334c1sewardj	 well. */
131998edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      if (sz != 4) goto decode_failure;
132008edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      t1 = newTemp(Ity_I32);
132018edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      t2 = newTemp(Ity_I32);
132028edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      /* Make up a 32-bit value (t1), with the old value of AX in the
132038edc36b45e95a7ec9879a25b80390129f1d334c1sewardj         bottom 16 bits, and the old OSZACP bitmask in the upper 16
132048edc36b45e95a7ec9879a25b80390129f1d334c1sewardj         bits. */
132058edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      assign(t1,
132068edc36b45e95a7ec9879a25b80390129f1d334c1sewardj             binop(Iop_16HLto32,
132078edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                   unop(Iop_32to16,
132088edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                        mk_x86g_calculate_eflags_all()),
132098edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                   getIReg(2, R_EAX)
132108edc36b45e95a7ec9879a25b80390129f1d334c1sewardj            ));
132118edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      /* Call the helper fn, to get a new AX and OSZACP value, and
132128edc36b45e95a7ec9879a25b80390129f1d334c1sewardj         poke both back into the guest state.  Also pass the helper
132138edc36b45e95a7ec9879a25b80390129f1d334c1sewardj         the actual opcode so it knows which of the 4 instructions it
132148edc36b45e95a7ec9879a25b80390129f1d334c1sewardj         is doing the computation for. */
132158edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      vassert(opc == 0x27 || opc == 0x2F || opc == 0x37 || opc == 0x3F);
132168edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      assign(t2,
132178edc36b45e95a7ec9879a25b80390129f1d334c1sewardj              mkIRExprCCall(
132188edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                 Ity_I32, 0/*regparm*/, "x86g_calculate_daa_das_aaa_aas",
132198edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                 &x86g_calculate_daa_das_aaa_aas,
132208edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
132218edc36b45e95a7ec9879a25b80390129f1d334c1sewardj            ));
132228edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
132238edc36b45e95a7ec9879a25b80390129f1d334c1sewardj
132248edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
132258edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
132268edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     stmt( IRStmt_Put( OFFB_CC_DEP1,
132278edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                       binop(Iop_And32,
132288edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                             binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
132298edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                             mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
132308edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                                    | X86G_CC_MASK_A | X86G_CC_MASK_Z
132318edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                                    | X86G_CC_MASK_S| X86G_CC_MASK_O )
132328edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                            )
132338edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                      )
132348edc36b45e95a7ec9879a25b80390129f1d334c1sewardj         );
132358edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     /* Set NDEP even though it isn't used.  This makes redundant-PUT
132368edc36b45e95a7ec9879a25b80390129f1d334c1sewardj        elimination of previous stores to this field work better. */
132378edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
132388edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     switch (opc) {
132398edc36b45e95a7ec9879a25b80390129f1d334c1sewardj        case 0x27: DIP("daa\n"); break;
132408edc36b45e95a7ec9879a25b80390129f1d334c1sewardj        case 0x2F: DIP("das\n"); break;
132418edc36b45e95a7ec9879a25b80390129f1d334c1sewardj        case 0x37: DIP("aaa\n"); break;
132428edc36b45e95a7ec9879a25b80390129f1d334c1sewardj        case 0x3F: DIP("aas\n"); break;
132438edc36b45e95a7ec9879a25b80390129f1d334c1sewardj        default: vassert(0);
132448edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     }
132458edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     break;
132468edc36b45e95a7ec9879a25b80390129f1d334c1sewardj
13247321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj   case 0xD4: /* AAM */
13248321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj   case 0xD5: /* AAD */
13249321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      d32 = getIByte(delta); delta++;
13250321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      if (sz != 4 || d32 != 10) goto decode_failure;
13251321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      t1 = newTemp(Ity_I32);
13252321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      t2 = newTemp(Ity_I32);
13253321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      /* Make up a 32-bit value (t1), with the old value of AX in the
13254321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         bottom 16 bits, and the old OSZACP bitmask in the upper 16
13255321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         bits. */
13256321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      assign(t1,
13257321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj             binop(Iop_16HLto32,
13258321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                   unop(Iop_32to16,
13259321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                        mk_x86g_calculate_eflags_all()),
13260321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                   getIReg(2, R_EAX)
13261321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj            ));
13262321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      /* Call the helper fn, to get a new AX and OSZACP value, and
13263321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         poke both back into the guest state.  Also pass the helper
13264321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         the actual opcode so it knows which of the 2 instructions it
13265321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         is doing the computation for. */
13266321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      assign(t2,
13267321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj              mkIRExprCCall(
13268321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                 Ity_I32, 0/*regparm*/, "x86g_calculate_aad_aam",
13269321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                 &x86g_calculate_aad_aam,
13270321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
13271321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj            ));
13272321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
13273321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj
13274321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
13275321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13276321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      stmt( IRStmt_Put( OFFB_CC_DEP1,
13277321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                        binop(Iop_And32,
13278321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                              binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
13279321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                              mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
13280321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                                     | X86G_CC_MASK_A | X86G_CC_MASK_Z
13281321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                                     | X86G_CC_MASK_S| X86G_CC_MASK_O )
13282321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                             )
13283321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                       )
13284321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj          );
13285321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      /* Set NDEP even though it isn't used.  This makes
13286321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         redundant-PUT elimination of previous stores to this field
13287321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         work better. */
13288321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13289321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj
13290321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      DIP(opc == 0xD4 ? "aam\n" : "aad\n");
13291321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      break;
132921c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
132931c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* ------------------------ CWD/CDQ -------------------- */
132941c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
132951c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   case 0x98: /* CBW */
132961c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      if (sz == 4) {
132971c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj         putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
132981c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj         DIP("cwde\n");
132991c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      } else {
1330047341042b1b4140b5b4b42983df7bec015f7beecsewardj         vassert(sz == 2);
1330147341042b1b4140b5b4b42983df7bec015f7beecsewardj         putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
1330247341042b1b4140b5b4b42983df7bec015f7beecsewardj         DIP("cbw\n");
133031c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      }
133041c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      break;
1330564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1330664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x99: /* CWD/CDQ */
1330764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      ty = szToITy(sz);
1330864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      putIReg(sz, R_EDX,
1330964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj                  binop(mkSizedOp(ty,Iop_Sar8),
1331064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj                        getIReg(sz, R_EAX),
133119ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj                        mkU8(sz == 2 ? 15 : 31)) );
1331264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
1331364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      break;
1331464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
13315bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   /* ------------------------ FPU ops -------------------- */
13316bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
13317bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   case 0x9E: /* SAHF */
13318bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      codegen_SAHF();
13319bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      DIP("sahf\n");
13320bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      break;
13321bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
133228dfdc8a059e35940fe96371360cae39d9724cea9sewardj   case 0x9F: /* LAHF */
133238dfdc8a059e35940fe96371360cae39d9724cea9sewardj      codegen_LAHF();
133248dfdc8a059e35940fe96371360cae39d9724cea9sewardj      DIP("lahf\n");
133258dfdc8a059e35940fe96371360cae39d9724cea9sewardj      break;
133268dfdc8a059e35940fe96371360cae39d9724cea9sewardj
13327bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   case 0x9B: /* FWAIT */
13328bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      /* ignore? */
13329bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      DIP("fwait\n");
13330bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      break;
13331bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
13332d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xD8:
13333d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xD9:
13334d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xDA:
13335d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xDB:
13336d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xDC:
13337d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xDD:
13338d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xDE:
13339d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xDF: {
1334052d049186d07991237a825ec88aa7f1f303edb70sewardj      Int  delta0    = delta;
13341d1725d18b61bf7912a9099686179faef5815dba1sewardj      Bool decode_OK = False;
13342d1725d18b61bf7912a9099686179faef5815dba1sewardj      delta = dis_FPU ( &decode_OK, sorb, delta );
13343d1725d18b61bf7912a9099686179faef5815dba1sewardj      if (!decode_OK) {
13344d1725d18b61bf7912a9099686179faef5815dba1sewardj         delta = delta0;
13345d1725d18b61bf7912a9099686179faef5815dba1sewardj         goto decode_failure;
13346d1725d18b61bf7912a9099686179faef5815dba1sewardj      }
13347d1725d18b61bf7912a9099686179faef5815dba1sewardj      break;
13348d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
133490611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
133500611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   /* ------------------------ INC & DEC ------------------ */
133510611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
133520611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x40: /* INC eAX */
133530611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x41: /* INC eCX */
133540611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x42: /* INC eDX */
133550611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x43: /* INC eBX */
133560611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x44: /* INC eSP */
133570611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x45: /* INC eBP */
133580611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x46: /* INC eSI */
133590611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x47: /* INC eDI */
133600611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      vassert(sz == 2 || sz == 4);
133610611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      ty = szToITy(sz);
133620611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      t1 = newTemp(ty);
133630611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      assign( t1, binop(mkSizedOp(ty,Iop_Add8),
133640611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                        getIReg(sz, (UInt)(opc - 0x40)),
133650611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                        mkU(ty,1)) );
133660611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      setFlags_INC_DEC( True, t1, ty );
133670611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
133680611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
133690611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
133700611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
133710611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x48: /* DEC eAX */
133720611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x49: /* DEC eCX */
133730611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x4A: /* DEC eDX */
133740611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x4B: /* DEC eBX */
133750611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x4C: /* DEC eSP */
133760611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x4D: /* DEC eBP */
133770611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x4E: /* DEC eSI */
133780611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x4F: /* DEC eDI */
133790611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      vassert(sz == 2 || sz == 4);
133800611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      ty = szToITy(sz);
133810611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      t1 = newTemp(ty);
133820611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
133830611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                        getIReg(sz, (UInt)(opc - 0x48)),
133840611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                        mkU(ty,1)) );
133850611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      setFlags_INC_DEC( False, t1, ty );
133860611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
133870611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
133880611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
133890611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
133900611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   /* ------------------------ INT ------------------------ */
133910611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
13392322bfa0201be78c22f1ec1d579355bd2a7ac51aesewardj   case 0xCC: /* INT 3 */
13393c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      jmp_lit(&dres, Ijk_SigTRAP, ((Addr32)guest_EIP_bbstart)+delta);
13394c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      vassert(dres.whatNext == Dis_StopHere);
13395322bfa0201be78c22f1ec1d579355bd2a7ac51aesewardj      DIP("int $0x3\n");
13396322bfa0201be78c22f1ec1d579355bd2a7ac51aesewardj      break;
13397322bfa0201be78c22f1ec1d579355bd2a7ac51aesewardj
133980611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0xCD: /* INT imm8 */
133990611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      d32 = getIByte(delta); delta++;
134000f50004eefdf1066682a016efb4a57c092ae2da2sewardj
13401d660d41d4174e44f284bad3264601662ed68d4a1sewardj      /* For any of the cases where we emit a jump (that is, for all
13402d660d41d4174e44f284bad3264601662ed68d4a1sewardj         currently handled cases), it's important that all ArchRegs
13403d660d41d4174e44f284bad3264601662ed68d4a1sewardj         carry their up-to-date value at this point.  So we declare an
13404d660d41d4174e44f284bad3264601662ed68d4a1sewardj         end-of-block here, which forces any TempRegs caching ArchRegs
13405d660d41d4174e44f284bad3264601662ed68d4a1sewardj         to be flushed. */
13406d660d41d4174e44f284bad3264601662ed68d4a1sewardj
1340784af676f5b09efab952869c755bc5cdb7468e55bsewardj      /* Handle int $0x3F .. $0x4F by synthesising a segfault and a
134080f50004eefdf1066682a016efb4a57c092ae2da2sewardj         restart of this instruction (hence the "-2" two lines below,
134090f50004eefdf1066682a016efb4a57c092ae2da2sewardj         to get the restart EIP to be this instruction.  This is
134100f50004eefdf1066682a016efb4a57c092ae2da2sewardj         probably Linux-specific and it would be more correct to only
1341184af676f5b09efab952869c755bc5cdb7468e55bsewardj         do this if the VexAbiInfo says that is what we should do.
1341284af676f5b09efab952869c755bc5cdb7468e55bsewardj         This used to handle just 0x40-0x43; Jikes RVM uses a larger
1341384af676f5b09efab952869c755bc5cdb7468e55bsewardj         range (0x3F-0x49), and this allows some slack as well. */
1341484af676f5b09efab952869c755bc5cdb7468e55bsewardj      if (d32 >= 0x3F && d32 <= 0x4F) {
13415c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jmp_lit(&dres, Ijk_SigSEGV, ((Addr32)guest_EIP_bbstart)+delta-2);
13416c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
13417b173774421d015736c2316b5e6e998e7de545a5cflorian         DIP("int $0x%x\n", d32);
134180f50004eefdf1066682a016efb4a57c092ae2da2sewardj         break;
134190f50004eefdf1066682a016efb4a57c092ae2da2sewardj      }
134200f50004eefdf1066682a016efb4a57c092ae2da2sewardj
13421d660d41d4174e44f284bad3264601662ed68d4a1sewardj      /* Handle int $0x80 (linux syscalls), int $0x81 and $0x82
134223e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj         (darwin syscalls), int $0x91 (Solaris syscalls) and int $0xD2
134233e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj         (Solaris fasttrap syscalls).  As part of this, note where we are, so we
13424e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         can back up the guest to this point if the syscall needs to
13425e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         be restarted. */
134263e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj      IRJumpKind jump_kind;
134273e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj      switch (d32) {
134283e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj      case 0x80:
134293e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj         jump_kind = Ijk_Sys_int128;
13430d660d41d4174e44f284bad3264601662ed68d4a1sewardj         break;
134313e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj      case 0x81:
134323e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj         jump_kind = Ijk_Sys_int129;
13433d660d41d4174e44f284bad3264601662ed68d4a1sewardj         break;
134343e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj      case 0x82:
134353e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj         jump_kind = Ijk_Sys_int130;
134363e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj         break;
134373e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj      case 0x91:
134383e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj         jump_kind = Ijk_Sys_int145;
134393e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj         break;
134403e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj      case 0xD2:
134413e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj         jump_kind = Ijk_Sys_int210;
13442d660d41d4174e44f284bad3264601662ed68d4a1sewardj         break;
134433e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj      default:
134443e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj         /* none of the above */
134453e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj         goto decode_failure;
13446d660d41d4174e44f284bad3264601662ed68d4a1sewardj      }
13447d660d41d4174e44f284bad3264601662ed68d4a1sewardj
134483e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj      stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
134493e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj                        mkU32(guest_EIP_curr_instr) ) );
134503e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj      jmp_lit(&dres, jump_kind, ((Addr32)guest_EIP_bbstart)+delta);
134513e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj      vassert(dres.whatNext == Dis_StopHere);
13452b173774421d015736c2316b5e6e998e7de545a5cflorian      DIP("int $0x%x\n", d32);
134533e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj      break;
134540611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
1345577b86be374085943e902075b305ff047a053aac6sewardj   /* ------------------------ Jcond, byte offset --------- */
1345677b86be374085943e902075b305ff047a053aac6sewardj
1345777b86be374085943e902075b305ff047a053aac6sewardj   case 0xEB: /* Jb (jump, byte offset) */
134589e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
1345977b86be374085943e902075b305ff047a053aac6sewardj      delta++;
13460beac530a718fcc646bc61fe60a86f599df54e1d7florian      if (resteerOkFn( callback_opaque, (Addr32)d32) ) {
13461984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         dres.whatNext   = Dis_ResteerU;
134620eaa35ff5569f09129073be27c2f827926f7010dflorian         dres.continueAt = (Addr32)d32;
13463ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj      } else {
13464c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jmp_lit(&dres, Ijk_Boring, d32);
13465c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
13466ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj      }
1346777b86be374085943e902075b305ff047a053aac6sewardj      DIP("jmp-8 0x%x\n", d32);
1346877b86be374085943e902075b305ff047a053aac6sewardj      break;
134690611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
134700611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0xE9: /* Jv (jump, 16/32 offset) */
134710611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      vassert(sz == 4); /* JRS added 2004 July 11 */
134729e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj      d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta);
134730611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      delta += sz;
13474beac530a718fcc646bc61fe60a86f599df54e1d7florian      if (resteerOkFn( callback_opaque, (Addr32)d32) ) {
13475984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         dres.whatNext   = Dis_ResteerU;
134760eaa35ff5569f09129073be27c2f827926f7010dflorian         dres.continueAt = (Addr32)d32;
13477ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj      } else {
13478c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jmp_lit(&dres, Ijk_Boring, d32);
13479c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
13480ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj      }
134810611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      DIP("jmp 0x%x\n", d32);
134820611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
13483e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
13484e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x70:
13485e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x71:
13486e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x72: /* JBb/JNAEb (jump below) */
13487e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x73: /* JNBb/JAEb (jump not below) */
13488e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x74: /* JZb/JEb (jump zero) */
13489e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x75: /* JNZb/JNEb (jump not zero) */
13490e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x76: /* JBEb/JNAb (jump below or equal) */
13491e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x77: /* JNBEb/JAb (jump not below or equal) */
13492e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x78: /* JSb (jump negative) */
13493e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x79: /* JSb (jump not negative) */
13494e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x7A: /* JP (jump parity even) */
13495e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x7B: /* JNP/JPO (jump parity odd) */
13496e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x7C: /* JLb/JNGEb (jump less) */
13497e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x7D: /* JGEb/JNLb (jump greater or equal) */
13498e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x7E: /* JLEb/JNGb (jump less or equal) */
13499e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x7F: /* JGb/JNLEb (jump greater) */
13500984d9b164dd17f07e603c41fe1e506e641e57d18sewardj    { Int    jmpDelta;
1350155085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* comment  = "";
13502984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      jmpDelta = (Int)getSDisp8(delta);
13503984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      vassert(-128 <= jmpDelta && jmpDelta < 128);
13504984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + jmpDelta;
13505e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      delta++;
13506984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      if (resteerCisOk
13507984d9b164dd17f07e603c41fe1e506e641e57d18sewardj          && vex_control.guest_chase_cond
135080d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj          && (Addr32)d32 != (Addr32)guest_EIP_bbstart
13509984d9b164dd17f07e603c41fe1e506e641e57d18sewardj          && jmpDelta < 0
13510beac530a718fcc646bc61fe60a86f599df54e1d7florian          && resteerOkFn( callback_opaque, (Addr32)d32) ) {
13511984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         /* Speculation: assume this backward branch is taken.  So we
13512984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            need to emit a side-exit to the insn following this one,
13513984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            on the negation of the condition, and continue at the
135140d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj            branch target address (d32).  If we wind up back at the
135150d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj            first instruction of the trace, just stop; it's better to
135160d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj            let the IR loop unroller handle that case. */
13517dbf550c3bb7d82eca7ea1436466dd51761fb7d4bsewardj         stmt( IRStmt_Exit(
13518dbf550c3bb7d82eca7ea1436466dd51761fb7d4bsewardj                  mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
13519dbf550c3bb7d82eca7ea1436466dd51761fb7d4bsewardj                  Ijk_Boring,
13520c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                  IRConst_U32(guest_EIP_bbstart+delta),
13521c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                  OFFB_EIP ) );
13522984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         dres.whatNext   = Dis_ResteerC;
135230eaa35ff5569f09129073be27c2f827926f7010dflorian         dres.continueAt = (Addr32)d32;
13524984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         comment = "(assumed taken)";
13525984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      }
13526984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      else
13527984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      if (resteerCisOk
13528984d9b164dd17f07e603c41fe1e506e641e57d18sewardj          && vex_control.guest_chase_cond
135290d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj          && (Addr32)d32 != (Addr32)guest_EIP_bbstart
13530984d9b164dd17f07e603c41fe1e506e641e57d18sewardj          && jmpDelta >= 0
13531984d9b164dd17f07e603c41fe1e506e641e57d18sewardj          && resteerOkFn( callback_opaque,
13532beac530a718fcc646bc61fe60a86f599df54e1d7florian                          (Addr32)(guest_EIP_bbstart+delta)) ) {
13533984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         /* Speculation: assume this forward branch is not taken.  So
13534984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            we need to emit a side-exit to d32 (the dest) and continue
13535984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            disassembling at the insn immediately following this
13536984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            one. */
13537984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         stmt( IRStmt_Exit(
13538984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                  mk_x86g_calculate_condition((X86Condcode)(opc - 0x70)),
13539984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                  Ijk_Boring,
13540c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                  IRConst_U32(d32),
13541c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                  OFFB_EIP ) );
13542984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         dres.whatNext   = Dis_ResteerC;
135430eaa35ff5569f09129073be27c2f827926f7010dflorian         dres.continueAt = guest_EIP_bbstart + delta;
13544984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         comment = "(assumed not taken)";
13545984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      }
13546984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      else {
13547984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         /* Conservative default translation - end the block at this
13548984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            point. */
13549c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jcc_01( &dres, (X86Condcode)(opc - 0x70),
13550984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                 (Addr32)(guest_EIP_bbstart+delta), d32);
13551c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
13552dbf550c3bb7d82eca7ea1436466dd51761fb7d4bsewardj      }
13553984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      DIP("j%s-8 0x%x %s\n", name_X86Condcode(opc - 0x70), d32, comment);
13554e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      break;
13555984d9b164dd17f07e603c41fe1e506e641e57d18sewardj    }
13556e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
13557dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   case 0xE3: /* JECXZ (for JCXZ see above) */
13558baa660847fc52547575169bcf2be772cd16364a6sewardj      if (sz != 4) goto decode_failure;
135599e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13560dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj      delta ++;
13561458a6f8809554fc459d90043e032f7c579620c97sewardj      stmt( IRStmt_Exit(
13562dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj               binop(Iop_CmpEQ32, getIReg(4,R_ECX), mkU32(0)),
13563893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj            Ijk_Boring,
13564c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            IRConst_U32(d32),
13565c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            OFFB_EIP
13566dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj          ));
13567dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj      DIP("jecxz 0x%x\n", d32);
13568458a6f8809554fc459d90043e032f7c579620c97sewardj      break;
13569458a6f8809554fc459d90043e032f7c579620c97sewardj
13570baa660847fc52547575169bcf2be772cd16364a6sewardj   case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
13571baa660847fc52547575169bcf2be772cd16364a6sewardj   case 0xE1: /* LOOPE  disp8: decrement count, jump if count != 0 && ZF==1 */
13572baa660847fc52547575169bcf2be772cd16364a6sewardj   case 0xE2: /* LOOP   disp8: decrement count, jump if count != 0 */
13573baa660847fc52547575169bcf2be772cd16364a6sewardj    { /* Again, the docs say this uses ECX/CX as a count depending on
13574baa660847fc52547575169bcf2be772cd16364a6sewardj         the address size override, not the operand one.  Since we
13575baa660847fc52547575169bcf2be772cd16364a6sewardj         don't handle address size overrides, I guess that means
13576baa660847fc52547575169bcf2be772cd16364a6sewardj         ECX. */
13577baa660847fc52547575169bcf2be772cd16364a6sewardj      IRExpr* zbit  = NULL;
13578baa660847fc52547575169bcf2be772cd16364a6sewardj      IRExpr* count = NULL;
13579baa660847fc52547575169bcf2be772cd16364a6sewardj      IRExpr* cond  = NULL;
1358055085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* xtra = NULL;
13581baa660847fc52547575169bcf2be772cd16364a6sewardj
13582baa660847fc52547575169bcf2be772cd16364a6sewardj      if (sz != 4) goto decode_failure;
13583baa660847fc52547575169bcf2be772cd16364a6sewardj      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13584baa660847fc52547575169bcf2be772cd16364a6sewardj      delta++;
13585baa660847fc52547575169bcf2be772cd16364a6sewardj      putIReg(4, R_ECX, binop(Iop_Sub32, getIReg(4,R_ECX), mkU32(1)));
13586baa660847fc52547575169bcf2be772cd16364a6sewardj
13587baa660847fc52547575169bcf2be772cd16364a6sewardj      count = getIReg(4,R_ECX);
13588baa660847fc52547575169bcf2be772cd16364a6sewardj      cond = binop(Iop_CmpNE32, count, mkU32(0));
13589baa660847fc52547575169bcf2be772cd16364a6sewardj      switch (opc) {
13590baa660847fc52547575169bcf2be772cd16364a6sewardj         case 0xE2:
13591baa660847fc52547575169bcf2be772cd16364a6sewardj            xtra = "";
13592baa660847fc52547575169bcf2be772cd16364a6sewardj            break;
13593baa660847fc52547575169bcf2be772cd16364a6sewardj         case 0xE1:
13594baa660847fc52547575169bcf2be772cd16364a6sewardj            xtra = "e";
13595baa660847fc52547575169bcf2be772cd16364a6sewardj            zbit = mk_x86g_calculate_condition( X86CondZ );
13596baa660847fc52547575169bcf2be772cd16364a6sewardj	    cond = mkAnd1(cond, zbit);
13597baa660847fc52547575169bcf2be772cd16364a6sewardj            break;
13598baa660847fc52547575169bcf2be772cd16364a6sewardj         case 0xE0:
13599baa660847fc52547575169bcf2be772cd16364a6sewardj            xtra = "ne";
13600baa660847fc52547575169bcf2be772cd16364a6sewardj            zbit = mk_x86g_calculate_condition( X86CondNZ );
13601baa660847fc52547575169bcf2be772cd16364a6sewardj	    cond = mkAnd1(cond, zbit);
13602baa660847fc52547575169bcf2be772cd16364a6sewardj            break;
13603baa660847fc52547575169bcf2be772cd16364a6sewardj         default:
13604baa660847fc52547575169bcf2be772cd16364a6sewardj	    vassert(0);
13605baa660847fc52547575169bcf2be772cd16364a6sewardj      }
13606c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U32(d32), OFFB_EIP) );
13607baa660847fc52547575169bcf2be772cd16364a6sewardj
13608baa660847fc52547575169bcf2be772cd16364a6sewardj      DIP("loop%s 0x%x\n", xtra, d32);
13609baa660847fc52547575169bcf2be772cd16364a6sewardj      break;
13610baa660847fc52547575169bcf2be772cd16364a6sewardj    }
136111813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
136121813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   /* ------------------------ IMUL ----------------------- */
136131813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
136141813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   case 0x69: /* IMUL Iv, Ev, Gv */
136151813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
136161813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      break;
136171813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   case 0x6B: /* IMUL Ib, Ev, Gv */
136181813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
136191813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      break;
136200611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
136210611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   /* ------------------------ MOV ------------------------ */
136220611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
136230611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x88: /* MOV Gb,Eb */
136240611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      delta = dis_mov_G_E(sorb, 1, delta);
136250611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
13626c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
13627c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   case 0x89: /* MOV Gv,Ev */
13628c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      delta = dis_mov_G_E(sorb, sz, delta);
13629c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      break;
13630c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
13631c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0x8A: /* MOV Eb,Gb */
13632c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      delta = dis_mov_E_G(sorb, 1, delta);
13633c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
13634e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
13635e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   case 0x8B: /* MOV Ev,Gv */
13636e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      delta = dis_mov_E_G(sorb, sz, delta);
13637e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
13638e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
13639e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x8D: /* LEA M,Gv */
13640e9460bd464d943658e8a2ac4489fb2baa0e16682sewardj      if (sz != 4)
13641e9460bd464d943658e8a2ac4489fb2baa0e16682sewardj         goto decode_failure;
13642e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      modrm = getIByte(delta);
13643e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      if (epartIsReg(modrm))
13644e9460bd464d943658e8a2ac4489fb2baa0e16682sewardj         goto decode_failure;
13645e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      /* NOTE!  this is the one place where a segment override prefix
13646e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj         has no effect on the address calculation.  Therefore we pass
13647e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj         zero instead of sorb here. */
13648e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
13649e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      delta += alen;
13650940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      putIReg(sz, gregOfRM(modrm), mkexpr(addr));
13651e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
13652e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                            nameIReg(sz,gregOfRM(modrm)));
13653e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
13654e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
13655063f02f7e77ca024d24786bec402ca296a05bd6esewardj   case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
13656063f02f7e77ca024d24786bec402ca296a05bd6esewardj      delta = dis_mov_Sw_Ew(sorb, sz, delta);
13657063f02f7e77ca024d24786bec402ca296a05bd6esewardj      break;
13658063f02f7e77ca024d24786bec402ca296a05bd6esewardj
136597df596b1e36840e2d74c90aa55589934add61ccfsewardj   case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
136607df596b1e36840e2d74c90aa55589934add61ccfsewardj      delta = dis_mov_Ew_Sw(sorb, delta);
136617df596b1e36840e2d74c90aa55589934add61ccfsewardj      break;
136627df596b1e36840e2d74c90aa55589934add61ccfsewardj
136634385281d538e7052cc6dc45998bdecd4672c4036sewardj   case 0xA0: /* MOV Ob,AL */
136644385281d538e7052cc6dc45998bdecd4672c4036sewardj      sz = 1;
136654385281d538e7052cc6dc45998bdecd4672c4036sewardj      /* Fall through ... */
136660c12ea83187de020a5484b4327e2427ea3451380sewardj   case 0xA1: /* MOV Ov,eAX */
136670c12ea83187de020a5484b4327e2427ea3451380sewardj      d32 = getUDisp32(delta); delta += 4;
136680c12ea83187de020a5484b4327e2427ea3451380sewardj      ty = szToITy(sz);
136690c12ea83187de020a5484b4327e2427ea3451380sewardj      addr = newTemp(Ity_I32);
136700c12ea83187de020a5484b4327e2427ea3451380sewardj      assign( addr, handleSegOverride(sorb, mkU32(d32)) );
136710c12ea83187de020a5484b4327e2427ea3451380sewardj      putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
136720c12ea83187de020a5484b4327e2427ea3451380sewardj      DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
136730c12ea83187de020a5484b4327e2427ea3451380sewardj                                d32, nameIReg(sz,R_EAX));
136740c12ea83187de020a5484b4327e2427ea3451380sewardj      break;
136750c12ea83187de020a5484b4327e2427ea3451380sewardj
13676180e8b39d5b4271e64634162986749c43536647csewardj   case 0xA2: /* MOV Ob,AL */
13677180e8b39d5b4271e64634162986749c43536647csewardj      sz = 1;
13678180e8b39d5b4271e64634162986749c43536647csewardj      /* Fall through ... */
13679750f407b6be1aac303964a219acf0a6de8b8c4dasewardj   case 0xA3: /* MOV eAX,Ov */
13680750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      d32 = getUDisp32(delta); delta += 4;
13681750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      ty = szToITy(sz);
13682750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      addr = newTemp(Ity_I32);
13683750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13684750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
13685750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
13686750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                                sorbTxt(sorb), d32);
13687750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      break;
13688e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
13689c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB0: /* MOV imm,AL */
13690c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB1: /* MOV imm,CL */
13691c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB2: /* MOV imm,DL */
13692c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB3: /* MOV imm,BL */
13693c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB4: /* MOV imm,AH */
13694c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB5: /* MOV imm,CH */
13695c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB6: /* MOV imm,DH */
13696c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB7: /* MOV imm,BH */
13697c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      d32 = getIByte(delta); delta += 1;
13698c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      putIReg(1, opc-0xB0, mkU8(d32));
13699c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
13700c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
137017ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj
13702e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xB8: /* MOV imm,eAX */
13703e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xB9: /* MOV imm,eCX */
13704e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xBA: /* MOV imm,eDX */
13705e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xBB: /* MOV imm,eBX */
13706e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xBC: /* MOV imm,eSP */
13707e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xBD: /* MOV imm,eBP */
13708e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xBE: /* MOV imm,eSI */
13709e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xBF: /* MOV imm,eDI */
13710e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      d32 = getUDisp(sz,delta); delta += sz;
13711e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
13712e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
13713e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      break;
13714e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
137151bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj   case 0xC6: /* C6 /0 = MOV Ib,Eb */
1371677b86be374085943e902075b305ff047a053aac6sewardj      sz = 1;
137171bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj      goto maybe_do_Mov_I_E;
137181bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj   case 0xC7: /* C7 /0 = MOV Iv,Ev */
137191bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj      goto maybe_do_Mov_I_E;
13720e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
137211bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj   maybe_do_Mov_I_E:
13722e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      modrm = getIByte(delta);
137231bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj      if (gregOfRM(modrm) == 0) {
137241bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj         if (epartIsReg(modrm)) {
137251bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            delta++; /* mod/rm byte */
137261bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            d32 = getUDisp(sz,delta); delta += sz;
137271bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
137281bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
137291bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj                                     nameIReg(sz,eregOfRM(modrm)));
137301bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj         } else {
137311bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            addr = disAMode ( &alen, sorb, delta, dis_buf );
137321bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            delta += alen;
137331bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            d32 = getUDisp(sz,delta); delta += sz;
137341bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
137351bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
137361bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj         }
137371bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj         break;
13738e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      }
137391bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj      goto decode_failure;
13740e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
137411813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   /* ------------------------ opl imm, A ----------------- */
137421813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
137431813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   case 0x04: /* ADD Ib, AL */
13744a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_Add8, True, delta, "add" );
137451813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      break;
1374677b86be374085943e902075b305ff047a053aac6sewardj   case 0x05: /* ADD Iv, eAX */
13747a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_Add8, True, delta, "add" );
1374877b86be374085943e902075b305ff047a053aac6sewardj      break;
1374977b86be374085943e902075b305ff047a053aac6sewardj
13750940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   case 0x0C: /* OR Ib, AL */
13751a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_Or8, True, delta, "or" );
13752940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
137538229288c4fb1331c1e638bacdd55566e1caad9edsewardj   case 0x0D: /* OR Iv, eAX */
13754a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
137558229288c4fb1331c1e638bacdd55566e1caad9edsewardj      break;
137568229288c4fb1331c1e638bacdd55566e1caad9edsewardj
13757eca203688d1c4f2d4c3327ebf0f4124e098492e8sewardj   case 0x14: /* ADC Ib, AL */
13758eca203688d1c4f2d4c3327ebf0f4124e098492e8sewardj      delta = dis_op_imm_A(  1, True, Iop_Add8, True, delta, "adc" );
13759eca203688d1c4f2d4c3327ebf0f4124e098492e8sewardj      break;
13760a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   case 0x15: /* ADC Iv, eAX */
13761eca203688d1c4f2d4c3327ebf0f4124e098492e8sewardj      delta = dis_op_imm_A( sz, True, Iop_Add8, True, delta, "adc" );
13762a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      break;
13763a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj
137642fbae083dad486e8e623011b4dd68ba204c2a228sewardj   case 0x1C: /* SBB Ib, AL */
137652fbae083dad486e8e623011b4dd68ba204c2a228sewardj      delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
137662fbae083dad486e8e623011b4dd68ba204c2a228sewardj      break;
137672fbae083dad486e8e623011b4dd68ba204c2a228sewardj   case 0x1D: /* SBB Iv, eAX */
137682fbae083dad486e8e623011b4dd68ba204c2a228sewardj      delta = dis_op_imm_A( sz, True, Iop_Sub8, True, delta, "sbb" );
137692fbae083dad486e8e623011b4dd68ba204c2a228sewardj      break;
137702fbae083dad486e8e623011b4dd68ba204c2a228sewardj
13771940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   case 0x24: /* AND Ib, AL */
13772a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_And8, True, delta, "and" );
13773940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
13774c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0x25: /* AND Iv, eAX */
13775a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
13776c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
137770611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
137780611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x2C: /* SUB Ib, AL */
13779a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_Sub8, True, delta, "sub" );
137800611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
1378168511549b138ef55c8d31088cb0f20a72d83ab2bsewardj   case 0x2D: /* SUB Iv, eAX */
13782a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
1378368511549b138ef55c8d31088cb0f20a72d83ab2bsewardj      break;
1378468511549b138ef55c8d31088cb0f20a72d83ab2bsewardj
137851c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   case 0x34: /* XOR Ib, AL */
13786a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_Xor8, True, delta, "xor" );
137871c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      break;
13788caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   case 0x35: /* XOR Iv, eAX */
13789a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
13790caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      break;
13791caca9d0d3729c36af6ae02b0654cb289101248cbsewardj
137920611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x3C: /* CMP Ib, AL */
13793a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_Sub8, False, delta, "cmp" );
137940611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
137950611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x3D: /* CMP Iv, eAX */
13796a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
137970611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
137980611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
1379977b86be374085943e902075b305ff047a053aac6sewardj   case 0xA8: /* TEST Ib, AL */
13800a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_And8, False, delta, "test" );
1380177b86be374085943e902075b305ff047a053aac6sewardj      break;
13802c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xA9: /* TEST Iv, eAX */
13803a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
13804c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
13805c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
138061c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* ------------------------ opl Ev, Gv ----------------- */
138071c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
1380889cd09353a584000edaaa61558b27253bdea7452sewardj   case 0x02: /* ADD Eb,Gb */
1380989cd09353a584000edaaa61558b27253bdea7452sewardj      delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
1381089cd09353a584000edaaa61558b27253bdea7452sewardj      break;
138119334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x03: /* ADD Ev,Gv */
13812180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
138139334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      break;
138149334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
138157ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj   case 0x0A: /* OR Eb,Gb */
13816180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
138177ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      break;
13818c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0x0B: /* OR Ev,Gv */
13819180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
13820c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
138212fbae083dad486e8e623011b4dd68ba204c2a228sewardj
138222fbae083dad486e8e623011b4dd68ba204c2a228sewardj   case 0x12: /* ADC Eb,Gb */
138232fbae083dad486e8e623011b4dd68ba204c2a228sewardj      delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
138242fbae083dad486e8e623011b4dd68ba204c2a228sewardj      break;
13825c4eaff3aa358fc5c73b534c7e78366555184244fsewardj   case 0x13: /* ADC Ev,Gv */
13826c4eaff3aa358fc5c73b534c7e78366555184244fsewardj      delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
13827c4eaff3aa358fc5c73b534c7e78366555184244fsewardj      break;
13828c4eaff3aa358fc5c73b534c7e78366555184244fsewardj
138292fbae083dad486e8e623011b4dd68ba204c2a228sewardj   case 0x1A: /* SBB Eb,Gb */
138302fbae083dad486e8e623011b4dd68ba204c2a228sewardj      delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
138312fbae083dad486e8e623011b4dd68ba204c2a228sewardj      break;
13832180e8b39d5b4271e64634162986749c43536647csewardj   case 0x1B: /* SBB Ev,Gv */
13833180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
13834180e8b39d5b4271e64634162986749c43536647csewardj      break;
13835180e8b39d5b4271e64634162986749c43536647csewardj
138361c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   case 0x22: /* AND Eb,Gb */
138371c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
138381c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      break;
13839940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   case 0x23: /* AND Ev,Gv */
13840180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
13841940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
13842940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
13843180e8b39d5b4271e64634162986749c43536647csewardj   case 0x2A: /* SUB Eb,Gb */
13844180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
13845180e8b39d5b4271e64634162986749c43536647csewardj      break;
138460611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x2B: /* SUB Ev,Gv */
13847180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
138480611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
13849c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
13850c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0x32: /* XOR Eb,Gb */
13851180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
13852c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
138531813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   case 0x33: /* XOR Ev,Gv */
13854180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
138551813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      break;
138561813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
13857c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0x3A: /* CMP Eb,Gb */
13858180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
13859c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
13860e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   case 0x3B: /* CMP Ev,Gv */
13861180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
13862e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      break;
13863e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
138640611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x84: /* TEST Eb,Gb */
13865180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
138660611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
13867e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   case 0x85: /* TEST Ev,Gv */
13868180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
13869e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
13870e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
13871180e8b39d5b4271e64634162986749c43536647csewardj   /* ------------------------ opl Gv, Ev ----------------- */
13872180e8b39d5b4271e64634162986749c43536647csewardj
13873180e8b39d5b4271e64634162986749c43536647csewardj   case 0x00: /* ADD Gb,Eb */
13874e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13875e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Add8, True, 1, delta, "add" );
13876180e8b39d5b4271e64634162986749c43536647csewardj      break;
13877e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   case 0x01: /* ADD Gv,Ev */
13878e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13879e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Add8, True, sz, delta, "add" );
13880e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
13881e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
13882940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   case 0x08: /* OR Gb,Eb */
13883e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13884e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Or8, True, 1, delta, "or" );
13885940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
138869334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x09: /* OR Gv,Ev */
13887e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13888e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Or8, True, sz, delta, "or" );
138899334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      break;
138909334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
13891a238471814bd386aeb58a76718b41e68b1a794b2sewardj   case 0x10: /* ADC Gb,Eb */
13892e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13893e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Add8, True, 1, delta, "adc" );
13894a238471814bd386aeb58a76718b41e68b1a794b2sewardj      break;
13895caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   case 0x11: /* ADC Gv,Ev */
13896e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13897e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Add8, True, sz, delta, "adc" );
13898caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      break;
13899caca9d0d3729c36af6ae02b0654cb289101248cbsewardj
13900a238471814bd386aeb58a76718b41e68b1a794b2sewardj   case 0x18: /* SBB Gb,Eb */
13901e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13902e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Sub8, True, 1, delta, "sbb" );
13903a238471814bd386aeb58a76718b41e68b1a794b2sewardj      break;
13904caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   case 0x19: /* SBB Gv,Ev */
13905e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13906e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Sub8, True, sz, delta, "sbb" );
13907caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      break;
13908caca9d0d3729c36af6ae02b0654cb289101248cbsewardj
13909a238471814bd386aeb58a76718b41e68b1a794b2sewardj   case 0x20: /* AND Gb,Eb */
13910e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13911e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_And8, True, 1, delta, "and" );
13912a238471814bd386aeb58a76718b41e68b1a794b2sewardj      break;
139130611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x21: /* AND Gv,Ev */
13914e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13915e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_And8, True, sz, delta, "and" );
139160611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
139170611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
13918180e8b39d5b4271e64634162986749c43536647csewardj   case 0x28: /* SUB Gb,Eb */
13919e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13920e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Sub8, True, 1, delta, "sub" );
13921180e8b39d5b4271e64634162986749c43536647csewardj      break;
13922e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   case 0x29: /* SUB Gv,Ev */
13923e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13924e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Sub8, True, sz, delta, "sub" );
13925e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
13926e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
13927c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0x30: /* XOR Gb,Eb */
13928e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13929e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Xor8, True, 1, delta, "xor" );
13930c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
13931e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x31: /* XOR Gv,Ev */
13932e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13933e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Xor8, True, sz, delta, "xor" );
13934e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      break;
13935e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
139360611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x38: /* CMP Gb,Eb */
13937e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13938e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Sub8, False, 1, delta, "cmp" );
139390611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
13940e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   case 0x39: /* CMP Gv,Ev */
13941e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13942e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Sub8, False, sz, delta, "cmp" );
13943e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      break;
13944e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
139459334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   /* ------------------------ POP ------------------------ */
139469334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
139479334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x58: /* POP eAX */
139489334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x59: /* POP eCX */
139499334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x5A: /* POP eDX */
139509334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x5B: /* POP eBX */
139519334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x5D: /* POP eBP */
139529334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x5E: /* POP eSI */
139539334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x5F: /* POP eDI */
139549334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x5C: /* POP eSP */
139559334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      vassert(sz == 2 || sz == 4);
139569334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
139579334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      assign(t2, getIReg(4, R_ESP));
139589334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
139599334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
139609334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      putIReg(sz, opc-0x58, mkexpr(t1));
139619334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
139629334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      break;
139639334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
13964a238471814bd386aeb58a76718b41e68b1a794b2sewardj   case 0x9D: /* POPF */
13965a238471814bd386aeb58a76718b41e68b1a794b2sewardj      vassert(sz == 2 || sz == 4);
13966a238471814bd386aeb58a76718b41e68b1a794b2sewardj      t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13967a238471814bd386aeb58a76718b41e68b1a794b2sewardj      assign(t2, getIReg(4, R_ESP));
13968c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
13969a238471814bd386aeb58a76718b41e68b1a794b2sewardj      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
13970a238471814bd386aeb58a76718b41e68b1a794b2sewardj
139710e9a0f551e190b475150dcd6bc4500033eb05338sewardj      /* Generate IR to set %EFLAGS{O,S,Z,A,C,P,D,ID,AC} from the
139720e9a0f551e190b475150dcd6bc4500033eb05338sewardj	 value in t1. */
139730e9a0f551e190b475150dcd6bc4500033eb05338sewardj      set_EFLAGS_from_value( t1, True/*emit_AC_emwarn*/,
139740e9a0f551e190b475150dcd6bc4500033eb05338sewardj                                 ((Addr32)guest_EIP_bbstart)+delta );
139756d26984a0df6a7d20b658bac6edf869eb872cca3sewardj
13976a238471814bd386aeb58a76718b41e68b1a794b2sewardj      DIP("popf%c\n", nameISize(sz));
13977a238471814bd386aeb58a76718b41e68b1a794b2sewardj      break;
13978a238471814bd386aeb58a76718b41e68b1a794b2sewardj
13979bbdc6225e71309bd47b639aba9c799a0496c457esewardj   case 0x61: /* POPA */
13980bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* This is almost certainly wrong for sz==2.  So ... */
13981bbdc6225e71309bd47b639aba9c799a0496c457esewardj      if (sz != 4) goto decode_failure;
13982bbdc6225e71309bd47b639aba9c799a0496c457esewardj
13983bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* t5 is the old %ESP value. */
13984bbdc6225e71309bd47b639aba9c799a0496c457esewardj      t5 = newTemp(Ity_I32);
13985bbdc6225e71309bd47b639aba9c799a0496c457esewardj      assign( t5, getIReg(4, R_ESP) );
13986bbdc6225e71309bd47b639aba9c799a0496c457esewardj
13987bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* Reload all the registers, except %esp. */
13988bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
13989bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
13990bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
13991bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
13992bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* ignore saved %ESP */
13993bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
13994bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
13995bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
13996bbdc6225e71309bd47b639aba9c799a0496c457esewardj
13997bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* and move %ESP back up */
13998bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
13999bbdc6225e71309bd47b639aba9c799a0496c457esewardj
14000a3d1a66a58870e3afed8a9fe08336f859f6af3ebsewardj      DIP("popa%c\n", nameISize(sz));
14001bbdc6225e71309bd47b639aba9c799a0496c457esewardj      break;
14002feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
14003feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj   case 0x8F: /* POPL/POPW m32 */
14004fcff178bf2302f24b54957339082339a44ab5e71sewardj     { Int    len;
14005fcff178bf2302f24b54957339082339a44ab5e71sewardj       UChar  rm = getIByte(delta);
14006feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
14007feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       /* make sure this instruction is correct POP */
14008fcff178bf2302f24b54957339082339a44ab5e71sewardj       if (epartIsReg(rm) || gregOfRM(rm) != 0)
14009fcff178bf2302f24b54957339082339a44ab5e71sewardj          goto decode_failure;
14010feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       /* and has correct size */
14011fcff178bf2302f24b54957339082339a44ab5e71sewardj       if (sz != 4 && sz != 2)
14012fcff178bf2302f24b54957339082339a44ab5e71sewardj          goto decode_failure;
14013fcff178bf2302f24b54957339082339a44ab5e71sewardj       ty = szToITy(sz);
14014fcff178bf2302f24b54957339082339a44ab5e71sewardj
14015fcff178bf2302f24b54957339082339a44ab5e71sewardj       t1 = newTemp(Ity_I32); /* stack address */
14016fcff178bf2302f24b54957339082339a44ab5e71sewardj       t3 = newTemp(ty); /* data */
14017feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       /* set t1 to ESP: t1 = ESP */
14018feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       assign( t1, getIReg(4, R_ESP) );
14019feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       /* load M[ESP] to virtual register t3: t3 = M[t1] */
14020fcff178bf2302f24b54957339082339a44ab5e71sewardj       assign( t3, loadLE(ty, mkexpr(t1)) );
14021feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
14022feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       /* increase ESP; must be done before the STORE.  Intel manual says:
14023feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            If the ESP register is used as a base register for addressing
14024feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            a destination operand in memory, the POP instruction computes
14025feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            the effective address of the operand after it increments the
14026feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            ESP register.
14027feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       */
14028feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
14029feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
14030feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       /* resolve MODR/M */
14031feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       addr = disAMode ( &len, sorb, delta, dis_buf);
14032feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       storeLE( mkexpr(addr), mkexpr(t3) );
14033feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
14034fcff178bf2302f24b54957339082339a44ab5e71sewardj       DIP("pop%c %s\n", sz==2 ? 'w' : 'l', dis_buf);
14035feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
14036feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       delta += len;
14037feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       break;
14038feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj     }
14039feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
140405c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x1F: /* POP %DS */
140415c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_pop_segreg( R_DS, sz ); break;
140425c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x07: /* POP %ES */
140435c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_pop_segreg( R_ES, sz ); break;
140445c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x17: /* POP %SS */
140455c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_pop_segreg( R_SS, sz ); break;
14046d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14047d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   /* ------------------------ PUSH ----------------------- */
14048d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14049d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x50: /* PUSH eAX */
14050d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x51: /* PUSH eCX */
14051d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x52: /* PUSH eDX */
14052d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x53: /* PUSH eBX */
14053d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x55: /* PUSH eBP */
14054d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x56: /* PUSH eSI */
14055d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x57: /* PUSH eDI */
14056d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x54: /* PUSH eSP */
14057d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* This is the Right Way, in that the value to be pushed is
14058d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         established before %esp is changed, so that pushl %esp
14059d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         correctly pushes the old value. */
14060d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      vassert(sz == 2 || sz == 4);
14061d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      ty = sz==2 ? Ity_I16 : Ity_I32;
14062883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      t1 = newTemp(ty); t2 = newTemp(Ity_I32);
1406341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      assign(t1, getIReg(sz, opc-0x50));
1406441f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
1406541f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      putIReg(4, R_ESP, mkexpr(t2) );
1406641f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      storeLE(mkexpr(t2),mkexpr(t1));
14067d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
14068d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      break;
14069d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14070d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
140710c12ea83187de020a5484b4327e2427ea3451380sewardj   case 0x68: /* PUSH Iv */
140720c12ea83187de020a5484b4327e2427ea3451380sewardj      d32 = getUDisp(sz,delta); delta += sz;
140730c12ea83187de020a5484b4327e2427ea3451380sewardj      goto do_push_I;
14074741153c4301023a420ab45b8a10b8e1bac968822sewardj   case 0x6A: /* PUSH Ib, sign-extended to sz */
14075741153c4301023a420ab45b8a10b8e1bac968822sewardj      d32 = getSDisp8(delta); delta += 1;
14076741153c4301023a420ab45b8a10b8e1bac968822sewardj      goto do_push_I;
140770c12ea83187de020a5484b4327e2427ea3451380sewardj   do_push_I:
140780c12ea83187de020a5484b4327e2427ea3451380sewardj      ty = szToITy(sz);
140790c12ea83187de020a5484b4327e2427ea3451380sewardj      t1 = newTemp(Ity_I32); t2 = newTemp(ty);
140800c12ea83187de020a5484b4327e2427ea3451380sewardj      assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
140810c12ea83187de020a5484b4327e2427ea3451380sewardj      putIReg(4, R_ESP, mkexpr(t1) );
14082c4255a0df097f3d6740ec768fa145bca6921961bsewardj      /* stop mkU16 asserting if d32 is a negative 16-bit number
14083c4255a0df097f3d6740ec768fa145bca6921961bsewardj         (bug #132813) */
14084c4255a0df097f3d6740ec768fa145bca6921961bsewardj      if (ty == Ity_I16)
14085c4255a0df097f3d6740ec768fa145bca6921961bsewardj         d32 &= 0xFFFF;
140860c12ea83187de020a5484b4327e2427ea3451380sewardj      storeLE( mkexpr(t1), mkU(ty,d32) );
140870c12ea83187de020a5484b4327e2427ea3451380sewardj      DIP("push%c $0x%x\n", nameISize(sz), d32);
140880c12ea83187de020a5484b4327e2427ea3451380sewardj      break;
140890c12ea83187de020a5484b4327e2427ea3451380sewardj
14090a238471814bd386aeb58a76718b41e68b1a794b2sewardj   case 0x9C: /* PUSHF */ {
14091a238471814bd386aeb58a76718b41e68b1a794b2sewardj      vassert(sz == 2 || sz == 4);
14092a238471814bd386aeb58a76718b41e68b1a794b2sewardj
14093a238471814bd386aeb58a76718b41e68b1a794b2sewardj      t1 = newTemp(Ity_I32);
14094a238471814bd386aeb58a76718b41e68b1a794b2sewardj      assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
14095a238471814bd386aeb58a76718b41e68b1a794b2sewardj      putIReg(4, R_ESP, mkexpr(t1) );
14096a238471814bd386aeb58a76718b41e68b1a794b2sewardj
14097bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      /* Calculate OSZACP, and patch in fixed fields as per
14098bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         Intel docs.
14099bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         - bit 1 is always 1
14100bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         - bit 9 is Interrupt Enable (should always be 1 in user mode?)
14101bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      */
14102a238471814bd386aeb58a76718b41e68b1a794b2sewardj      t2 = newTemp(Ity_I32);
14103bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      assign( t2, binop(Iop_Or32,
14104bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj                        mk_x86g_calculate_eflags_all(),
14105bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj                        mkU32( (1<<1)|(1<<9) ) ));
14106a238471814bd386aeb58a76718b41e68b1a794b2sewardj
14107f9c74fef6758ac5e46c32a3e896d92343e34c049sewardj      /* Patch in the D flag.  This can simply be a copy of bit 10 of
14108f9c74fef6758ac5e46c32a3e896d92343e34c049sewardj         baseBlock[OFFB_DFLAG]. */
14109a238471814bd386aeb58a76718b41e68b1a794b2sewardj      t3 = newTemp(Ity_I32);
14110a238471814bd386aeb58a76718b41e68b1a794b2sewardj      assign( t3, binop(Iop_Or32,
14111a238471814bd386aeb58a76718b41e68b1a794b2sewardj                        mkexpr(t2),
14112a238471814bd386aeb58a76718b41e68b1a794b2sewardj                        binop(Iop_And32,
14113f9c74fef6758ac5e46c32a3e896d92343e34c049sewardj                              IRExpr_Get(OFFB_DFLAG,Ity_I32),
141145bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                              mkU32(1<<10)))
14115a238471814bd386aeb58a76718b41e68b1a794b2sewardj            );
14116006a6a2f15f48f705895a516d4883e8f8142e910sewardj
14117006a6a2f15f48f705895a516d4883e8f8142e910sewardj      /* And patch in the ID flag. */
14118006a6a2f15f48f705895a516d4883e8f8142e910sewardj      t4 = newTemp(Ity_I32);
14119006a6a2f15f48f705895a516d4883e8f8142e910sewardj      assign( t4, binop(Iop_Or32,
14120006a6a2f15f48f705895a516d4883e8f8142e910sewardj                        mkexpr(t3),
14121006a6a2f15f48f705895a516d4883e8f8142e910sewardj                        binop(Iop_And32,
141225bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                              binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
14123006a6a2f15f48f705895a516d4883e8f8142e910sewardj                                               mkU8(21)),
141245bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                              mkU32(1<<21)))
14125006a6a2f15f48f705895a516d4883e8f8142e910sewardj            );
14126006a6a2f15f48f705895a516d4883e8f8142e910sewardj
141276d26984a0df6a7d20b658bac6edf869eb872cca3sewardj      /* And patch in the AC flag. */
141286d26984a0df6a7d20b658bac6edf869eb872cca3sewardj      t5 = newTemp(Ity_I32);
141296d26984a0df6a7d20b658bac6edf869eb872cca3sewardj      assign( t5, binop(Iop_Or32,
141306d26984a0df6a7d20b658bac6edf869eb872cca3sewardj                        mkexpr(t4),
141316d26984a0df6a7d20b658bac6edf869eb872cca3sewardj                        binop(Iop_And32,
141326d26984a0df6a7d20b658bac6edf869eb872cca3sewardj                              binop(Iop_Shl32, IRExpr_Get(OFFB_ACFLAG,Ity_I32),
141336d26984a0df6a7d20b658bac6edf869eb872cca3sewardj                                               mkU8(18)),
141346d26984a0df6a7d20b658bac6edf869eb872cca3sewardj                              mkU32(1<<18)))
141356d26984a0df6a7d20b658bac6edf869eb872cca3sewardj            );
141366d26984a0df6a7d20b658bac6edf869eb872cca3sewardj
14137a238471814bd386aeb58a76718b41e68b1a794b2sewardj      /* if sz==2, the stored value needs to be narrowed. */
14138a238471814bd386aeb58a76718b41e68b1a794b2sewardj      if (sz == 2)
141396d26984a0df6a7d20b658bac6edf869eb872cca3sewardj        storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t5)) );
14140a238471814bd386aeb58a76718b41e68b1a794b2sewardj      else
141416d26984a0df6a7d20b658bac6edf869eb872cca3sewardj        storeLE( mkexpr(t1), mkexpr(t5) );
14142a238471814bd386aeb58a76718b41e68b1a794b2sewardj
14143a238471814bd386aeb58a76718b41e68b1a794b2sewardj      DIP("pushf%c\n", nameISize(sz));
14144a238471814bd386aeb58a76718b41e68b1a794b2sewardj      break;
14145a238471814bd386aeb58a76718b41e68b1a794b2sewardj   }
14146a238471814bd386aeb58a76718b41e68b1a794b2sewardj
14147bbdc6225e71309bd47b639aba9c799a0496c457esewardj   case 0x60: /* PUSHA */
14148bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* This is almost certainly wrong for sz==2.  So ... */
14149bbdc6225e71309bd47b639aba9c799a0496c457esewardj      if (sz != 4) goto decode_failure;
14150bbdc6225e71309bd47b639aba9c799a0496c457esewardj
14151bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* This is the Right Way, in that the value to be pushed is
14152bbdc6225e71309bd47b639aba9c799a0496c457esewardj         established before %esp is changed, so that pusha
14153bbdc6225e71309bd47b639aba9c799a0496c457esewardj         correctly pushes the old %esp value.  New value of %esp is
14154bbdc6225e71309bd47b639aba9c799a0496c457esewardj         pushed at start. */
14155bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* t0 is the %ESP value we're going to push. */
14156bbdc6225e71309bd47b639aba9c799a0496c457esewardj      t0 = newTemp(Ity_I32);
14157bbdc6225e71309bd47b639aba9c799a0496c457esewardj      assign( t0, getIReg(4, R_ESP) );
14158bbdc6225e71309bd47b639aba9c799a0496c457esewardj
14159bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* t5 will be the new %ESP value. */
14160bbdc6225e71309bd47b639aba9c799a0496c457esewardj      t5 = newTemp(Ity_I32);
14161bbdc6225e71309bd47b639aba9c799a0496c457esewardj      assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
14162bbdc6225e71309bd47b639aba9c799a0496c457esewardj
14163bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* Update guest state before prodding memory. */
14164bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4, R_ESP, mkexpr(t5));
14165bbdc6225e71309bd47b639aba9c799a0496c457esewardj
14166bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* Dump all the registers. */
14167bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
14168bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
14169bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
14170bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
14171bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
14172bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
14173bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
14174bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
14175bbdc6225e71309bd47b639aba9c799a0496c457esewardj
14176bbdc6225e71309bd47b639aba9c799a0496c457esewardj      DIP("pusha%c\n", nameISize(sz));
14177bbdc6225e71309bd47b639aba9c799a0496c457esewardj      break;
14178bbdc6225e71309bd47b639aba9c799a0496c457esewardj
141795c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x0E: /* PUSH %CS */
141805c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_push_segreg( R_CS, sz ); break;
141815c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x1E: /* PUSH %DS */
141825c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_push_segreg( R_DS, sz ); break;
141835c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x06: /* PUSH %ES */
141845c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_push_segreg( R_ES, sz ); break;
141855c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x16: /* PUSH %SS */
141865c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_push_segreg( R_SS, sz ); break;
14187458a6f8809554fc459d90043e032f7c579620c97sewardj
14188458a6f8809554fc459d90043e032f7c579620c97sewardj   /* ------------------------ SCAS et al ----------------- */
14189458a6f8809554fc459d90043e032f7c579620c97sewardj
14190458a6f8809554fc459d90043e032f7c579620c97sewardj   case 0xA4: /* MOVS, no REP prefix */
14191458a6f8809554fc459d90043e032f7c579620c97sewardj   case 0xA5:
141929c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      if (sorb != 0)
141939c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj         goto decode_failure; /* else dis_string_op asserts */
14194458a6f8809554fc459d90043e032f7c579620c97sewardj      dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
14195458a6f8809554fc459d90043e032f7c579620c97sewardj      break;
14196458a6f8809554fc459d90043e032f7c579620c97sewardj
141978d4d223b7a4c77d4b8bb3e2c59ff87369e2b0127sewardj  case 0xA6: /* CMPSb, no REP prefix */
1419833b53540401e9796039e647b6e91248b8b944b0esewardj  case 0xA7:
141999c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      if (sorb != 0)
142009c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj         goto decode_failure; /* else dis_string_op asserts */
142019c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
142029c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      break;
1420333b53540401e9796039e647b6e91248b8b944b0esewardj
14204883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   case 0xAA: /* STOS, no REP prefix */
1420547341042b1b4140b5b4b42983df7bec015f7beecsewardj   case 0xAB:
142069c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      if (sorb != 0)
142079c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj         goto decode_failure; /* else dis_string_op asserts */
14208883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
14209883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      break;
1421033b53540401e9796039e647b6e91248b8b944b0esewardj
1421110ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   case 0xAC: /* LODS, no REP prefix */
1421210ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   case 0xAD:
142139c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      if (sorb != 0)
142149c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj         goto decode_failure; /* else dis_string_op asserts */
1421510ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj      dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
1421610ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj      break;
142172d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj
142182d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj   case 0xAE: /* SCAS, no REP prefix */
142192d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj   case 0xAF:
142209c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      if (sorb != 0)
142219c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj         goto decode_failure; /* else dis_string_op asserts */
142222d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
142232d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      break;
1422464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1422564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1422664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0xFC: /* CLD */
14227eeb9ef8549a9c4aa15cbfbda52e20703d778fc61sewardj      stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
1422864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      DIP("cld\n");
1422964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      break;
1423064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
142311813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   case 0xFD: /* STD */
142321813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
142331813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      DIP("std\n");
142341813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      break;
142351813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
14236bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj   case 0xF8: /* CLC */
14237bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj   case 0xF9: /* STC */
14238bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj   case 0xF5: /* CMC */
14239bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      t0 = newTemp(Ity_I32);
14240bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      t1 = newTemp(Ity_I32);
14241bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      assign( t0, mk_x86g_calculate_eflags_all() );
14242bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      switch (opc) {
14243bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         case 0xF8:
14244bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            assign( t1, binop(Iop_And32, mkexpr(t0),
14245bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj                                         mkU32(~X86G_CC_MASK_C)));
14246bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            DIP("clc\n");
14247bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            break;
14248bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         case 0xF9:
14249bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            assign( t1, binop(Iop_Or32, mkexpr(t0),
14250bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj                                        mkU32(X86G_CC_MASK_C)));
14251bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            DIP("stc\n");
14252bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            break;
14253bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         case 0xF5:
14254bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            assign( t1, binop(Iop_Xor32, mkexpr(t0),
14255bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj                                         mkU32(X86G_CC_MASK_C)));
14256bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            DIP("cmc\n");
14257bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            break;
14258bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         default:
14259bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            vpanic("disInstr(x86)(clc/stc/cmc)");
14260bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      }
14261bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
14262bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14263bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
14264bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      /* Set NDEP even though it isn't used.  This makes redundant-PUT
14265bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         elimination of previous stores to this field work better. */
14266bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14267bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      break;
142688229288c4fb1331c1e638bacdd55566e1caad9edsewardj
14269a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj   case 0xD6: /* SALC */
14270a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      t0 = newTemp(Ity_I32);
14271a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      t1 = newTemp(Ity_I32);
14272a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      assign( t0,  binop(Iop_And32,
14273a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj                         mk_x86g_calculate_eflags_c(),
14274a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj                         mkU32(1)) );
14275a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      assign( t1, binop(Iop_Sar32,
14276a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj                        binop(Iop_Shl32, mkexpr(t0), mkU8(31)),
14277a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj                        mkU8(31)) );
14278a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      putIReg(1, R_EAX, unop(Iop_32to8, mkexpr(t1)) );
14279a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      DIP("salc\n");
14280a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      break;
14281a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj
142828229288c4fb1331c1e638bacdd55566e1caad9edsewardj   /* REPNE prefix insn */
142838229288c4fb1331c1e638bacdd55566e1caad9edsewardj   case 0xF2: {
14284068baa225ba96cd71e7852ba7588a93fae751b18sewardj      Addr32 eip_orig = guest_EIP_bbstart + delta_start;
142859c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      if (sorb != 0) goto decode_failure;
142868229288c4fb1331c1e638bacdd55566e1caad9edsewardj      abyte = getIByte(delta); delta++;
142878229288c4fb1331c1e638bacdd55566e1caad9edsewardj
142888229288c4fb1331c1e638bacdd55566e1caad9edsewardj      if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
142898229288c4fb1331c1e638bacdd55566e1caad9edsewardj
142908229288c4fb1331c1e638bacdd55566e1caad9edsewardj      switch (abyte) {
142918229288c4fb1331c1e638bacdd55566e1caad9edsewardj      /* According to the Intel manual, "repne movs" should never occur, but
142928229288c4fb1331c1e638bacdd55566e1caad9edsewardj       * in practice it has happened, so allow for it here... */
14293180e8b39d5b4271e64634162986749c43536647csewardj      case 0xA4: sz = 1;   /* REPNE MOVS<sz> */
14294cea9662b02446234636e6e5fb269504c5f37fc20sewardj      case 0xA5:
14295c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondNZ, dis_MOVS, sz, eip_orig,
14296c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "repne movs" );
14297cea9662b02446234636e6e5fb269504c5f37fc20sewardj         break;
14298842dfb44f7eb453e1c0f3cd58687cff1c5696922sewardj
14299842dfb44f7eb453e1c0f3cd58687cff1c5696922sewardj      case 0xA6: sz = 1;   /* REPNE CMP<sz> */
14300842dfb44f7eb453e1c0f3cd58687cff1c5696922sewardj      case 0xA7:
14301c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondNZ, dis_CMPS, sz, eip_orig,
14302c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "repne cmps" );
14303842dfb44f7eb453e1c0f3cd58687cff1c5696922sewardj         break;
14304842dfb44f7eb453e1c0f3cd58687cff1c5696922sewardj
14305b69a6fa7c67203189f94f6dcc15e3c0fcddb472bsewardj      case 0xAA: sz = 1;   /* REPNE STOS<sz> */
14306b69a6fa7c67203189f94f6dcc15e3c0fcddb472bsewardj      case 0xAB:
14307c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondNZ, dis_STOS, sz, eip_orig,
14308c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "repne stos" );
14309b69a6fa7c67203189f94f6dcc15e3c0fcddb472bsewardj         break;
14310b69a6fa7c67203189f94f6dcc15e3c0fcddb472bsewardj
143118229288c4fb1331c1e638bacdd55566e1caad9edsewardj      case 0xAE: sz = 1;   /* REPNE SCAS<sz> */
143122d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      case 0xAF:
14313c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondNZ, dis_SCAS, sz, eip_orig,
14314c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "repne scas" );
143158229288c4fb1331c1e638bacdd55566e1caad9edsewardj         break;
143168229288c4fb1331c1e638bacdd55566e1caad9edsewardj
143178229288c4fb1331c1e638bacdd55566e1caad9edsewardj      default:
143188229288c4fb1331c1e638bacdd55566e1caad9edsewardj         goto decode_failure;
143198229288c4fb1331c1e638bacdd55566e1caad9edsewardj      }
143208229288c4fb1331c1e638bacdd55566e1caad9edsewardj      break;
143218229288c4fb1331c1e638bacdd55566e1caad9edsewardj   }
1432264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1432364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
1432464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      for the rest, it means REP) */
1432564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0xF3: {
14326068baa225ba96cd71e7852ba7588a93fae751b18sewardj      Addr32 eip_orig = guest_EIP_bbstart + delta_start;
1432764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      abyte = getIByte(delta); delta++;
1432864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1432964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
1433064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
14331c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj      if (sorb != 0 && abyte != 0x0F) goto decode_failure;
14332c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj
1433364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      switch (abyte) {
14334c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj      case 0x0F:
14335c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         switch (getIByte(delta)) {
14336c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         /* On older CPUs, TZCNT behaves the same as BSF.  */
14337c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         case 0xBC: /* REP BSF Gv,Ev */
14338c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj            delta = dis_bs_E_G ( sorb, sz, delta + 1, True );
14339c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj            break;
14340c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         /* On older CPUs, LZCNT behaves the same as BSR.  */
14341c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         case 0xBD: /* REP BSR Gv,Ev */
14342c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj            delta = dis_bs_E_G ( sorb, sz, delta + 1, False );
14343c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj            break;
14344c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         default:
14345c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj            goto decode_failure;
14346c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         }
14347c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         break;
14348c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj
1434964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      case 0xA4: sz = 1;   /* REP MOVS<sz> */
1435064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      case 0xA5:
14351c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondAlways, dis_MOVS, sz, eip_orig,
14352c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "rep movs" );
1435364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj         break;
1435464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1435564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      case 0xA6: sz = 1;   /* REPE CMP<sz> */
143562d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      case 0xA7:
14357c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondZ, dis_CMPS, sz, eip_orig,
14358c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "repe cmps" );
1435964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj         break;
1436064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1436164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      case 0xAA: sz = 1;   /* REP STOS<sz> */
1436264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      case 0xAB:
14363c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondAlways, dis_STOS, sz, eip_orig,
14364c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "rep stos" );
1436564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj         break;
14366576f323f29ae7a17a0f8fbce520c1a007b3b9966sewardj
14367dfb038d88735770985d7403304ed6ae3044646eesewardj      case 0xAC: sz = 1;   /* REP LODS<sz> */
14368dfb038d88735770985d7403304ed6ae3044646eesewardj      case 0xAD:
14369c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondAlways, dis_LODS, sz, eip_orig,
14370c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "rep lods" );
14371dfb038d88735770985d7403304ed6ae3044646eesewardj         break;
14372dfb038d88735770985d7403304ed6ae3044646eesewardj
14373576f323f29ae7a17a0f8fbce520c1a007b3b9966sewardj      case 0xAE: sz = 1;   /* REPE SCAS<sz> */
14374576f323f29ae7a17a0f8fbce520c1a007b3b9966sewardj      case 0xAF:
14375c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondZ, dis_SCAS, sz, eip_orig,
14376c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "repe scas" );
14377576f323f29ae7a17a0f8fbce520c1a007b3b9966sewardj         break;
1437843b8df1af5787b806425aaa73aa363b6955c43cdsewardj
1437943b8df1af5787b806425aaa73aa363b6955c43cdsewardj      case 0x90:           /* REP NOP (PAUSE) */
1438043b8df1af5787b806425aaa73aa363b6955c43cdsewardj         /* a hint to the P4 re spin-wait loop */
1438143b8df1af5787b806425aaa73aa363b6955c43cdsewardj         DIP("rep nop (P4 pause)\n");
143827ec59f681fab67db360cfac258f6e07d5e394b8csewardj         /* "observe" the hint.  The Vex client needs to be careful not
143837ec59f681fab67db360cfac258f6e07d5e394b8csewardj            to cause very long delays as a result, though. */
14384c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jmp_lit(&dres, Ijk_Yield, ((Addr32)guest_EIP_bbstart)+delta);
14385c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
1438643b8df1af5787b806425aaa73aa363b6955c43cdsewardj         break;
1438743b8df1af5787b806425aaa73aa363b6955c43cdsewardj
143887d3d347d896b451d94d51232d4072551875014b7sewardj      case 0xC3:           /* REP RET -- same as normal ret? */
14389c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_ret(&dres, 0);
143907d3d347d896b451d94d51232d4072551875014b7sewardj         DIP("rep ret\n");
143917d3d347d896b451d94d51232d4072551875014b7sewardj         break;
1439264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1439364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      default:
1439464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj         goto decode_failure;
1439564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      }
1439664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      break;
1439764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   }
143980611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
143990611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   /* ------------------------ XCHG ----------------------- */
144000611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
14401c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   /* XCHG reg,mem automatically asserts LOCK# even without a LOCK
144021fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj      prefix; hence it must be translated with an IRCAS (at least, the
144031fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj      memory variant). */
144040611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x86: /* XCHG Gb,Eb */
144050611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      sz = 1;
144060611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      /* Fall through ... */
144070611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x87: /* XCHG Gv,Ev */
144080611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      modrm = getIByte(delta);
144090611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      ty = szToITy(sz);
144100611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      t1 = newTemp(ty); t2 = newTemp(ty);
144110611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      if (epartIsReg(modrm)) {
144125bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         assign(t1, getIReg(sz, eregOfRM(modrm)));
144135bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         assign(t2, getIReg(sz, gregOfRM(modrm)));
144145bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         putIReg(sz, gregOfRM(modrm), mkexpr(t1));
144155bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         putIReg(sz, eregOfRM(modrm), mkexpr(t2));
144160611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         delta++;
144170611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         DIP("xchg%c %s, %s\n",
144180611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj             nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
144190611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                            nameIReg(sz,eregOfRM(modrm)));
144200611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      } else {
14421e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         *expect_CAS = True;
144220c12ea83187de020a5484b4327e2427ea3451380sewardj         addr = disAMode ( &alen, sorb, delta, dis_buf );
144235bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         assign( t1, loadLE(ty,mkexpr(addr)) );
144245bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         assign( t2, getIReg(sz,gregOfRM(modrm)) );
14425e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         casLE( mkexpr(addr),
14426e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
144275bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
144285bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         delta += alen;
144290611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         DIP("xchg%c %s, %s\n", nameISize(sz),
144300611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                                nameIReg(sz,gregOfRM(modrm)), dis_buf);
144310611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      }
144320611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
14433e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
14434e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x90: /* XCHG eAX,eAX */
14435e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      DIP("nop\n");
14436e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      break;
1443764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x91: /* XCHG eAX,eCX */
1443864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x92: /* XCHG eAX,eDX */
1443964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x93: /* XCHG eAX,eBX */
1444064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x94: /* XCHG eAX,eSP */
1444164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x95: /* XCHG eAX,eBP */
1444264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x96: /* XCHG eAX,eSI */
1444364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x97: /* XCHG eAX,eDI */
1444464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
1444564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      break;
1444664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
14447048de4da3c356e4dcdba7c693d850027b7d67c34sewardj   /* ------------------------ XLAT ----------------------- */
14448048de4da3c356e4dcdba7c693d850027b7d67c34sewardj
14449048de4da3c356e4dcdba7c693d850027b7d67c34sewardj   case 0xD7: /* XLAT */
14450048de4da3c356e4dcdba7c693d850027b7d67c34sewardj      if (sz != 4) goto decode_failure; /* sz == 2 is also allowed (0x66) */
14451048de4da3c356e4dcdba7c693d850027b7d67c34sewardj      putIReg(
14452048de4da3c356e4dcdba7c693d850027b7d67c34sewardj         1,
14453048de4da3c356e4dcdba7c693d850027b7d67c34sewardj         R_EAX/*AL*/,
14454048de4da3c356e4dcdba7c693d850027b7d67c34sewardj         loadLE(Ity_I8,
14455048de4da3c356e4dcdba7c693d850027b7d67c34sewardj                handleSegOverride(
14456048de4da3c356e4dcdba7c693d850027b7d67c34sewardj                   sorb,
14457048de4da3c356e4dcdba7c693d850027b7d67c34sewardj                   binop(Iop_Add32,
14458048de4da3c356e4dcdba7c693d850027b7d67c34sewardj                         getIReg(4, R_EBX),
14459048de4da3c356e4dcdba7c693d850027b7d67c34sewardj                         unop(Iop_8Uto32, getIReg(1, R_EAX/*AL*/))))));
14460048de4da3c356e4dcdba7c693d850027b7d67c34sewardj
14461048de4da3c356e4dcdba7c693d850027b7d67c34sewardj      DIP("xlat%c [ebx]\n", nameISize(sz));
14462048de4da3c356e4dcdba7c693d850027b7d67c34sewardj      break;
14463d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj
14464d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   /* ------------------------ IN / OUT ----------------------- */
14465d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj
14466d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xE4: /* IN imm8, AL */
14467d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      sz = 1;
14468d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14469d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      abyte = getIByte(delta); delta++;
14470d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign(t1, mkU32( abyte & 0xFF ));
14471b173774421d015736c2316b5e6e998e7de545a5cflorian      DIP("in%c $%d,%s\n", nameISize(sz), abyte, nameIReg(sz,R_EAX));
14472d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_IN;
14473d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xE5: /* IN imm8, eAX */
14474d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      vassert(sz == 2 || sz == 4);
14475d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14476d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      abyte = getIByte(delta); delta++;
14477d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign(t1, mkU32( abyte & 0xFF ));
14478b173774421d015736c2316b5e6e998e7de545a5cflorian      DIP("in%c $%d,%s\n", nameISize(sz), abyte, nameIReg(sz,R_EAX));
14479d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_IN;
14480d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xEC: /* IN %DX, AL */
14481d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      sz = 1;
14482d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14483d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14484d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14485d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj                                         nameIReg(sz,R_EAX));
14486d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_IN;
14487d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xED: /* IN %DX, eAX */
14488d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      vassert(sz == 2 || sz == 4);
14489d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14490d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14491d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14492d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj                                         nameIReg(sz,R_EAX));
14493d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_IN;
14494d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   do_IN: {
14495d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      /* At this point, sz indicates the width, and t1 is a 32-bit
14496d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj         value giving port number. */
14497d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      IRDirty* d;
14498d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      vassert(sz == 1 || sz == 2 || sz == 4);
14499d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      ty = szToITy(sz);
14500d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t2 = newTemp(Ity_I32);
14501d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      d = unsafeIRDirty_1_N(
14502d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             t2,
14503d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             0/*regparms*/,
14504d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             "x86g_dirtyhelper_IN",
14505d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             &x86g_dirtyhelper_IN,
14506d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             mkIRExprVec_2( mkexpr(t1), mkU32(sz) )
14507d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj          );
14508d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      /* do the call, dumping the result in t2. */
14509d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      stmt( IRStmt_Dirty(d) );
14510d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      putIReg(sz, R_EAX, narrowTo( ty, mkexpr(t2) ) );
14511d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      break;
14512d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   }
14513d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj
14514d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xE6: /* OUT AL, imm8 */
14515d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      sz = 1;
14516d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14517d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      abyte = getIByte(delta); delta++;
14518d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign( t1, mkU32( abyte & 0xFF ) );
14519b173774421d015736c2316b5e6e998e7de545a5cflorian      DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), abyte);
14520d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_OUT;
14521d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xE7: /* OUT eAX, imm8 */
14522d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      vassert(sz == 2 || sz == 4);
14523d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14524d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      abyte = getIByte(delta); delta++;
14525d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign( t1, mkU32( abyte & 0xFF ) );
14526b173774421d015736c2316b5e6e998e7de545a5cflorian      DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), abyte);
14527d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_OUT;
14528d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xEE: /* OUT AL, %DX */
14529d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      sz = 1;
14530d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14531d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14532d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14533d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj                                          nameIReg(2,R_EDX));
14534d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_OUT;
14535d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xEF: /* OUT eAX, %DX */
14536d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      vassert(sz == 2 || sz == 4);
14537d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14538d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14539d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14540d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj                                          nameIReg(2,R_EDX));
14541d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_OUT;
14542d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   do_OUT: {
14543d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      /* At this point, sz indicates the width, and t1 is a 32-bit
14544d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj         value giving port number. */
14545d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      IRDirty* d;
14546d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      vassert(sz == 1 || sz == 2 || sz == 4);
14547d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      ty = szToITy(sz);
14548d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      d = unsafeIRDirty_0_N(
14549d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             0/*regparms*/,
14550d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             "x86g_dirtyhelper_OUT",
14551d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             &x86g_dirtyhelper_OUT,
14552d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             mkIRExprVec_3( mkexpr(t1),
14553d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj                            widenUto32( getIReg(sz, R_EAX) ),
14554d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj                            mkU32(sz) )
14555d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj          );
14556d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      stmt( IRStmt_Dirty(d) );
14557d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      break;
14558d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   }
145590611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
145600611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   /* ------------------------ (Grp1 extensions) ---------- */
145610611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
14562792d771d513e1ba805983848bf5873a75a44b3b0sewardj   case 0x82: /* Grp1 Ib,Eb too.  Apparently this is the same as
14563792d771d513e1ba805983848bf5873a75a44b3b0sewardj                 case 0x80, but only in 32-bit mode. */
14564792d771d513e1ba805983848bf5873a75a44b3b0sewardj      /* fallthru */
145650611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x80: /* Grp1 Ib,Eb */
145660611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      modrm = getIByte(delta);
145670611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      am_sz = lengthAMode(delta);
145680611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      sz    = 1;
145690611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      d_sz  = 1;
14570c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      d32   = getUChar(delta + am_sz);
14571e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
145720611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
14573e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
14574e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   case 0x81: /* Grp1 Iv,Ev */
14575e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      modrm = getIByte(delta);
14576e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      am_sz = lengthAMode(delta);
14577e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      d_sz  = sz;
14578e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      d32   = getUDisp(d_sz, delta + am_sz);
14579e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
14580e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
14581d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14582d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x83: /* Grp1 Ib,Ev */
14583d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      modrm = getIByte(delta);
14584d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      am_sz = lengthAMode(delta);
14585d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      d_sz  = 1;
14586d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      d32   = getSDisp8(delta + am_sz);
14587e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
14588d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      break;
14589d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14590c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   /* ------------------------ (Grp2 extensions) ---------- */
14591c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
14592d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xC0: { /* Grp2 Ib,Eb */
14593d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14594c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      modrm = getIByte(delta);
14595c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      am_sz = lengthAMode(delta);
14596c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      d_sz  = 1;
14597180e8b39d5b4271e64634162986749c43536647csewardj      d32   = getUChar(delta + am_sz);
14598c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      sz    = 1;
145996d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14600d51dc81599cba69ddc133f56c743205330f9dc40sewardj                         mkU8(d32 & 0xFF), NULL, &decode_OK );
14601d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14602d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14603c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
14604d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14605d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xC1: { /* Grp2 Ib,Ev */
14606d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14607c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      modrm = getIByte(delta);
14608e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      am_sz = lengthAMode(delta);
14609e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      d_sz  = 1;
14610180e8b39d5b4271e64634162986749c43536647csewardj      d32   = getUChar(delta + am_sz);
146116d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14612d51dc81599cba69ddc133f56c743205330f9dc40sewardj                         mkU8(d32 & 0xFF), NULL, &decode_OK );
14613d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14614d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14615e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      break;
14616d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14617d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xD0: { /* Grp2 1,Eb */
14618d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14619180e8b39d5b4271e64634162986749c43536647csewardj      modrm = getIByte(delta);
14620180e8b39d5b4271e64634162986749c43536647csewardj      am_sz = lengthAMode(delta);
14621180e8b39d5b4271e64634162986749c43536647csewardj      d_sz  = 0;
14622180e8b39d5b4271e64634162986749c43536647csewardj      d32   = 1;
14623180e8b39d5b4271e64634162986749c43536647csewardj      sz    = 1;
14624180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14625d51dc81599cba69ddc133f56c743205330f9dc40sewardj                         mkU8(d32), NULL, &decode_OK );
14626d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14627d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14628180e8b39d5b4271e64634162986749c43536647csewardj      break;
14629d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14630d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xD1: { /* Grp2 1,Ev */
14631d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14632c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      modrm = getUChar(delta);
14633c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      am_sz = lengthAMode(delta);
14634c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      d_sz  = 0;
14635c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      d32   = 1;
146366d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14637d51dc81599cba69ddc133f56c743205330f9dc40sewardj                         mkU8(d32), NULL, &decode_OK );
14638d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14639d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14640c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
14641d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14642d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xD2: { /* Grp2 CL,Eb */
14643d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
146448c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      modrm = getUChar(delta);
146458c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      am_sz = lengthAMode(delta);
146468c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      d_sz  = 0;
146478c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      sz    = 1;
146488c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14649d51dc81599cba69ddc133f56c743205330f9dc40sewardj                         getIReg(1,R_ECX), "%cl", &decode_OK );
14650d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14651d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
146528c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      break;
14653d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14654d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xD3: { /* Grp2 CL,Ev */
14655d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
146569334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      modrm = getIByte(delta);
146579334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      am_sz = lengthAMode(delta);
146589334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      d_sz  = 0;
146599334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14660d51dc81599cba69ddc133f56c743205330f9dc40sewardj                         getIReg(1,R_ECX), "%cl", &decode_OK );
14661d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14662d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
146639334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      break;
14664d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
146659334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
14666940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   /* ------------------------ (Grp3 extensions) ---------- */
14667940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
14668d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xF6: { /* Grp3 Eb */
14669d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14670e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp3 ( sorb, pfx_lock, 1, delta, &decode_OK );
14671d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14672d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14673940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
14674d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14675d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xF7: { /* Grp3 Ev */
14676d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14677e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp3 ( sorb, pfx_lock, sz, delta, &decode_OK );
14678d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14679d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14680940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
14681d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14682940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
14683c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   /* ------------------------ (Grp4 extensions) ---------- */
14684c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
14685d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xFE: { /* Grp4 Eb */
14686d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14687e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp4 ( sorb, pfx_lock, delta, &decode_OK );
14688d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14689d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14690c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
14691d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
146920611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
146930611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   /* ------------------------ (Grp5 extensions) ---------- */
146940611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
14695d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xFF: { /* Grp5 Ev */
14696d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14697e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp5 ( sorb, pfx_lock, sz, delta, &dres, &decode_OK );
14698d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14699d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
147000611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
14701d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14702e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
14703e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   /* ------------------------ Escapes to 2-byte opcodes -- */
14704e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
14705e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x0F: {
14706e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      opc = getIByte(delta); delta++;
14707e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      switch (opc) {
14708e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
14709490ad3820487e34854c46befcc9c755d6afc2519sewardj      /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
14710490ad3820487e34854c46befcc9c755d6afc2519sewardj
14711490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 0xBA: { /* Grp8 Ib,Ev */
14712490ad3820487e34854c46befcc9c755d6afc2519sewardj         Bool decode_OK = False;
14713490ad3820487e34854c46befcc9c755d6afc2519sewardj         modrm = getUChar(delta);
14714490ad3820487e34854c46befcc9c755d6afc2519sewardj         am_sz = lengthAMode(delta);
14715490ad3820487e34854c46befcc9c755d6afc2519sewardj         d32   = getSDisp8(delta + am_sz);
14716e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         delta = dis_Grp8_Imm ( sorb, pfx_lock, delta, modrm,
14717e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                am_sz, sz, d32, &decode_OK );
14718490ad3820487e34854c46befcc9c755d6afc2519sewardj         if (!decode_OK)
14719490ad3820487e34854c46befcc9c755d6afc2519sewardj            goto decode_failure;
14720490ad3820487e34854c46befcc9c755d6afc2519sewardj         break;
14721490ad3820487e34854c46befcc9c755d6afc2519sewardj      }
14722ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
14723ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
14724ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
14725ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      case 0xBC: /* BSF Gv,Ev */
14726ce646f23d71ac432c340667387aa4a5ce7d18099sewardj         delta = dis_bs_E_G ( sorb, sz, delta, True );
14727ce646f23d71ac432c340667387aa4a5ce7d18099sewardj         break;
14728ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      case 0xBD: /* BSR Gv,Ev */
14729ce646f23d71ac432c340667387aa4a5ce7d18099sewardj         delta = dis_bs_E_G ( sorb, sz, delta, False );
14730ce646f23d71ac432c340667387aa4a5ce7d18099sewardj         break;
147311c4208f37f1d835e655967ba70f5d4f4f6686392sewardj
147321c4208f37f1d835e655967ba70f5d4f4f6686392sewardj      /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
147331c4208f37f1d835e655967ba70f5d4f4f6686392sewardj
147341c4208f37f1d835e655967ba70f5d4f4f6686392sewardj      case 0xC8: /* BSWAP %eax */
147351c4208f37f1d835e655967ba70f5d4f4f6686392sewardj      case 0xC9:
147361c4208f37f1d835e655967ba70f5d4f4f6686392sewardj      case 0xCA:
14737b4666cfa1661348b621b88ab2309cc82d82cc13dsewardj      case 0xCB:
14738b4666cfa1661348b621b88ab2309cc82d82cc13dsewardj      case 0xCC:
14739b4666cfa1661348b621b88ab2309cc82d82cc13dsewardj      case 0xCD:
147401c4208f37f1d835e655967ba70f5d4f4f6686392sewardj      case 0xCE:
147411c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case 0xCF: /* BSWAP %edi */
147421c4208f37f1d835e655967ba70f5d4f4f6686392sewardj         /* AFAICS from the Intel docs, this only exists at size 4. */
14743021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         if (sz != 4) goto decode_failure;
14744021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj
147451c4208f37f1d835e655967ba70f5d4f4f6686392sewardj         t1 = newTemp(Ity_I32);
147461c4208f37f1d835e655967ba70f5d4f4f6686392sewardj         assign( t1, getIReg(4, opc-0xC8) );
14747021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         t2 = math_BSWAP(t1, Ity_I32);
147481c4208f37f1d835e655967ba70f5d4f4f6686392sewardj
147491c4208f37f1d835e655967ba70f5d4f4f6686392sewardj         putIReg(4, opc-0xC8, mkexpr(t2));
147501c4208f37f1d835e655967ba70f5d4f4f6686392sewardj         DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
147511c4208f37f1d835e655967ba70f5d4f4f6686392sewardj         break;
147521c4208f37f1d835e655967ba70f5d4f4f6686392sewardj
147531c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
147541c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
147551c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case 0xA3: /* BT Gv,Ev */
147560283430ee809d645864ddd2da5f450f88142b4cdsewardj         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpNone );
147571c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj         break;
14758e6709111d4af7becab76be5971eea568074174cdsewardj      case 0xB3: /* BTR Gv,Ev */
147590283430ee809d645864ddd2da5f450f88142b4cdsewardj         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpReset );
14760e6709111d4af7becab76be5971eea568074174cdsewardj         break;
147611c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case 0xAB: /* BTS Gv,Ev */
147620283430ee809d645864ddd2da5f450f88142b4cdsewardj         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpSet );
147631c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj         break;
147644963a42df83976b446e204c7f1eb587021bd94a3sewardj      case 0xBB: /* BTC Gv,Ev */
147650283430ee809d645864ddd2da5f450f88142b4cdsewardj         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpComp );
147664963a42df83976b446e204c7f1eb587021bd94a3sewardj         break;
14767458a6f8809554fc459d90043e032f7c579620c97sewardj
14768458a6f8809554fc459d90043e032f7c579620c97sewardj      /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
14769458a6f8809554fc459d90043e032f7c579620c97sewardj
147702d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      case 0x40:
147712d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      case 0x41:
14772458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
14773458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
14774458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
14775458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
14776458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
14777458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
14778ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      case 0x48: /* CMOVSb (cmov negative) */
14779458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x49: /* CMOVSb (cmov not negative) */
147802d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      case 0x4A: /* CMOVP (cmov parity even) */
147812d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      case 0x4B: /* CMOVNP (cmov parity odd) */
14782458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
14783458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
14784458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
14785458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
147862a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
14787458a6f8809554fc459d90043e032f7c579620c97sewardj         break;
14788458a6f8809554fc459d90043e032f7c579620c97sewardj
14789458a6f8809554fc459d90043e032f7c579620c97sewardj      /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
14790458a6f8809554fc459d90043e032f7c579620c97sewardj
14791c744e870f0831fb929a3853cdf42e6f1d3ff9fb6sewardj      case 0xB0: /* CMPXCHG Gb,Eb */
14792e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         delta = dis_cmpxchg_G_E ( sorb, pfx_lock, 1, delta );
14793c744e870f0831fb929a3853cdf42e6f1d3ff9fb6sewardj         break;
14794458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0xB1: /* CMPXCHG Gv,Ev */
14795e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         delta = dis_cmpxchg_G_E ( sorb, pfx_lock, sz, delta );
14796458a6f8809554fc459d90043e032f7c579620c97sewardj         break;
14797300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14798300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj      case 0xC7: { /* CMPXCHG8B Gv (0F C7 /1) */
14799e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp expdHi    = newTemp(Ity_I32);
14800e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp expdLo    = newTemp(Ity_I32);
14801e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp dataHi    = newTemp(Ity_I32);
14802e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp dataLo    = newTemp(Ity_I32);
14803e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp oldHi     = newTemp(Ity_I32);
14804e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp oldLo     = newTemp(Ity_I32);
14805300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         IRTemp flags_old = newTemp(Ity_I32);
14806300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         IRTemp flags_new = newTemp(Ity_I32);
14807e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp success   = newTemp(Ity_I1);
14808e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
14809e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* Translate this using a DCAS, even if there is no LOCK
14810e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            prefix.  Life is too short to bother with generating two
14811e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            different translations for the with/without-LOCK-prefix
14812e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            cases. */
14813e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         *expect_CAS = True;
14814300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14815300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj	 /* Decode, and generate address. */
14816e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (sz != 4) goto decode_failure;
14817300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         modrm = getIByte(delta);
14818300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         if (epartIsReg(modrm)) goto decode_failure;
14819300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         if (gregOfRM(modrm) != 1) goto decode_failure;
14820300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         addr = disAMode ( &alen, sorb, delta, dis_buf );
14821300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         delta += alen;
14822300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14823e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* Get the expected and new values. */
14824e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         assign( expdHi, getIReg(4,R_EDX) );
14825e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         assign( expdLo, getIReg(4,R_EAX) );
14826e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         assign( dataHi, getIReg(4,R_ECX) );
14827e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         assign( dataLo, getIReg(4,R_EBX) );
14828e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
14829e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* Do the DCAS */
14830e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         stmt( IRStmt_CAS(
14831e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  mkIRCAS( oldHi, oldLo,
14832e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           Iend_LE, mkexpr(addr),
14833e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           mkexpr(expdHi), mkexpr(expdLo),
14834e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           mkexpr(dataHi), mkexpr(dataLo)
14835e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               )));
14836e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
14837e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* success when oldHi:oldLo == expdHi:expdLo */
14838e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         assign( success,
148391fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj                 binop(Iop_CasCmpEQ32,
14840e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                       binop(Iop_Or32,
14841e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                             binop(Iop_Xor32, mkexpr(oldHi), mkexpr(expdHi)),
14842e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                             binop(Iop_Xor32, mkexpr(oldLo), mkexpr(expdLo))
14843e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                       ),
14844e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                       mkU32(0)
14845e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                 ));
14846e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
14847e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* If the DCAS is successful, that is to say oldHi:oldLo ==
14848e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            expdHi:expdLo, then put expdHi:expdLo back in EDX:EAX,
14849e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            which is where they came from originally.  Both the actual
14850e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            contents of these two regs, and any shadow values, are
14851e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            unchanged.  If the DCAS fails then we're putting into
14852e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            EDX:EAX the value seen in memory. */
14853e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         putIReg(4, R_EDX,
1485499dd03e04a6914d90d5fee727d61d76905334becflorian                    IRExpr_ITE( mkexpr(success),
1485599dd03e04a6914d90d5fee727d61d76905334becflorian                                mkexpr(expdHi), mkexpr(oldHi)
14856e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                ));
14857e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         putIReg(4, R_EAX,
1485899dd03e04a6914d90d5fee727d61d76905334becflorian                    IRExpr_ITE( mkexpr(success),
1485999dd03e04a6914d90d5fee727d61d76905334becflorian                                mkexpr(expdLo), mkexpr(oldLo)
14860e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                ));
14861e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
14862e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* Copy the success bit into the Z flag and leave the others
14863e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            unchanged */
14864300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         assign( flags_old, widenUto32(mk_x86g_calculate_eflags_all()));
14865300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         assign(
14866300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj            flags_new,
14867300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj            binop(Iop_Or32,
14868300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj                  binop(Iop_And32, mkexpr(flags_old),
14869300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj                                   mkU32(~X86G_CC_MASK_Z)),
14870300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj                  binop(Iop_Shl32,
14871300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj                        binop(Iop_And32,
14872e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                              unop(Iop_1Uto32, mkexpr(success)), mkU32(1)),
14873300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj                        mkU8(X86G_CC_SHIFT_Z)) ));
14874300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14875300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
14876300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
14877300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14878300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         /* Set NDEP even though it isn't used.  This makes
14879300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj            redundant-PUT elimination of previous stores to this field
14880300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj            work better. */
14881300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14882300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14883300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         /* Sheesh.  Aren't you glad it was me and not you that had to
14884300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj	    write and validate all this grunge? */
14885300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14886300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj	 DIP("cmpxchg8b %s\n", dis_buf);
14887300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj	 break;
14888300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj      }
14889300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14890588ea765122c1ecb97991eea513b12504e35d55esewardj      /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
14891588ea765122c1ecb97991eea513b12504e35d55esewardj
148927cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj      case 0xA2: { /* CPUID */
148937cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         /* Uses dirty helper:
148949df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj               void dirtyhelper_CPUID_sse[012] ( VexGuestX86State* )
148957cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj            declared to mod eax, wr ebx, ecx, edx
148967cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         */
148979df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         IRDirty* d     = NULL;
148989df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         void*    fAddr = NULL;
1489955085f8680acc89d727e321f3b34cae1a8c4093aflorian         const HChar* fName = NULL;
149006d7c8e41eb4de6b3a3e6f38946d335360eaf21b4philippe         if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE3) {
149016d7c8e41eb4de6b3a3e6f38946d335360eaf21b4philippe            fName = "x86g_dirtyhelper_CPUID_sse3";
149026d7c8e41eb4de6b3a3e6f38946d335360eaf21b4philippe            fAddr = &x86g_dirtyhelper_CPUID_sse3;
149035117ce116f47141cb23d1b49cc826e19323add97sewardj         }
149045117ce116f47141cb23d1b49cc826e19323add97sewardj         else
149057ffce011e8aa3c6dffedd003a0a0d9ed9b1b2d62philippe         if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2) {
149067ffce011e8aa3c6dffedd003a0a0d9ed9b1b2d62philippe            fName = "x86g_dirtyhelper_CPUID_sse2";
149077ffce011e8aa3c6dffedd003a0a0d9ed9b1b2d62philippe            fAddr = &x86g_dirtyhelper_CPUID_sse2;
149087ffce011e8aa3c6dffedd003a0a0d9ed9b1b2d62philippe         }
149097ffce011e8aa3c6dffedd003a0a0d9ed9b1b2d62philippe         else
149105117ce116f47141cb23d1b49cc826e19323add97sewardj         if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE1) {
149115117ce116f47141cb23d1b49cc826e19323add97sewardj            fName = "x86g_dirtyhelper_CPUID_sse1";
149125117ce116f47141cb23d1b49cc826e19323add97sewardj            fAddr = &x86g_dirtyhelper_CPUID_sse1;
149135117ce116f47141cb23d1b49cc826e19323add97sewardj         }
149145117ce116f47141cb23d1b49cc826e19323add97sewardj         else
149156c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         if (archinfo->hwcaps & VEX_HWCAPS_X86_MMXEXT) {
149166c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            fName = "x86g_dirtyhelper_CPUID_mmxext";
149176c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            fAddr = &x86g_dirtyhelper_CPUID_mmxext;
149186c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         }
149196c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         else
149205117ce116f47141cb23d1b49cc826e19323add97sewardj         if (archinfo->hwcaps == 0/*no SSE*/) {
149215117ce116f47141cb23d1b49cc826e19323add97sewardj            fName = "x86g_dirtyhelper_CPUID_sse0";
149225117ce116f47141cb23d1b49cc826e19323add97sewardj            fAddr = &x86g_dirtyhelper_CPUID_sse0;
149235117ce116f47141cb23d1b49cc826e19323add97sewardj         } else
149245117ce116f47141cb23d1b49cc826e19323add97sewardj            vpanic("disInstr(x86)(cpuid)");
149255117ce116f47141cb23d1b49cc826e19323add97sewardj
149269df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         vassert(fName); vassert(fAddr);
149279df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         d = unsafeIRDirty_0_N ( 0/*regparms*/,
14928ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                                 fName, fAddr, mkIRExprVec_1(IRExpr_GSPTR()) );
149297cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         /* declare guest state effects */
149307cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->nFxState = 4;
14931c9069f2908814843e9a4da00da9c8905440195a6sewardj         vex_bzero(&d->fxState, sizeof(d->fxState));
149327cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[0].fx     = Ifx_Modify;
149337cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[0].offset = OFFB_EAX;
149347cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[0].size   = 4;
149357cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[1].fx     = Ifx_Write;
149367cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[1].offset = OFFB_EBX;
149377cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[1].size   = 4;
1493832bfd3e057bf3e0b215b1d234398b4d7791eba9asewardj         d->fxState[2].fx     = Ifx_Modify;
149397cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[2].offset = OFFB_ECX;
149407cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[2].size   = 4;
149417cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[3].fx     = Ifx_Write;
149427cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[3].offset = OFFB_EDX;
149437cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[3].size   = 4;
149447cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         /* execute the dirty call, side-effecting guest state */
149457cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         stmt( IRStmt_Dirty(d) );
1494655860d8f317d0cbd28d56734766bca1a330f2362sewardj         /* CPUID is a serialising insn.  So, just in case someone is
1494755860d8f317d0cbd28d56734766bca1a330f2362sewardj            using it as a memory fence ... */
14948c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         stmt( IRStmt_MBE(Imbe_Fence) );
14949517a7d602150b0701ebb32fa837374da1c3c80c8sewardj         DIP("cpuid\n");
14950588ea765122c1ecb97991eea513b12504e35d55esewardj         break;
149517cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj      }
149527cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj
149535bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj//--          if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
149545bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj//--             goto decode_failure;
14955c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14956c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          t1 = newTemp(cb);
14957c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          t2 = newTemp(cb);
14958c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          t3 = newTemp(cb);
14959c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          t4 = newTemp(cb);
14960c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr0(cb, CALLM_S, 0);
14961c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14962c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, GET,   4, ArchReg, R_EAX, TempReg, t1);
14963c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, PUSH,  4, TempReg, t1);
14964c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14965c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, MOV,   4, Literal, 0, TempReg, t2);
14966c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uLiteral(cb, 0);
14967c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, PUSH,  4, TempReg, t2);
14968c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14969c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, MOV,   4, Literal, 0, TempReg, t3);
14970c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uLiteral(cb, 0);
14971c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, PUSH,  4, TempReg, t3);
14972c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14973c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, MOV,   4, Literal, 0, TempReg, t4);
14974c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uLiteral(cb, 0);
14975c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, PUSH,  4, TempReg, t4);
14976c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14977c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, CALLM, 0, Lit16,   VGOFF_(helper_CPUID));
14978c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
14979c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14980c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, POP,   4, TempReg, t4);
14981c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, PUT,   4, TempReg, t4, ArchReg, R_EDX);
14982c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14983c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, POP,   4, TempReg, t3);
14984c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, PUT,   4, TempReg, t3, ArchReg, R_ECX);
14985c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14986c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, POP,   4, TempReg, t2);
14987c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, PUT,   4, TempReg, t2, ArchReg, R_EBX);
14988c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14989c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, POP,   4, TempReg, t1);
14990c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, PUT,   4, TempReg, t1, ArchReg, R_EAX);
14991c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14992c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr0(cb, CALLM_E, 0);
14993c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          DIP("cpuid\n");
14994c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          break;
14995c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
149969334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
149979334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
149989334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      case 0xB6: /* MOVZXb Eb,Gv */
149996ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj         if (sz != 2 && sz != 4)
150006ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj            goto decode_failure;
150016ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj         delta = dis_movx_E_G ( sorb, delta, 1, sz, False );
150029334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj         break;
150036ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj
15004940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      case 0xB7: /* MOVZXw Ew,Gv */
150056ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj         if (sz != 4)
150066ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj            goto decode_failure;
15007940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
15008940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         break;
15009940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
150100611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      case 0xBE: /* MOVSXb Eb,Gv */
150116ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj         if (sz != 2 && sz != 4)
150126ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj            goto decode_failure;
150136ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj         delta = dis_movx_E_G ( sorb, delta, 1, sz, True );
150140611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         break;
150156ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj
150167ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      case 0xBF: /* MOVSXw Ew,Gv */
1501733ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         if (sz != 4 && /* accept movsww, sigh, see #250799 */sz != 2)
150186ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj            goto decode_failure;
1501933ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         delta = dis_movx_E_G ( sorb, delta, 2, sz, True );
150207ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj         break;
150217ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj
15022c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
15023c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
15024c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       case 0xC3: /* MOVNTI Gv,Ev */
15025c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          vg_assert(sz == 4);
15026c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          modrm = getUChar(eip);
15027c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          vg_assert(!epartIsReg(modrm));
15028c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          t1 = newTemp(cb);
15029c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
15030c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          pair = disAMode ( cb, sorb, eip, dis_buf );
15031c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          t2 = LOW24(pair);
15032c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          eip += HI8(pair);
15033c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
15034c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
15035c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          break;
15036cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
15037cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj      /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
15038cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
15039cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj      case 0xAF: /* IMUL Ev, Gv */
150402a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         delta = dis_mul_E_G ( sorb, sz, delta );
15041cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj         break;
15042e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
15043ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj      /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
15044ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj
15045ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj      case 0x1F:
15046ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj         modrm = getUChar(delta);
15047ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj         if (epartIsReg(modrm)) goto decode_failure;
15048ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj         addr = disAMode ( &alen, sorb, delta, dis_buf );
15049ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj         delta += alen;
15050ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj         DIP("nop%c %s\n", nameISize(sz), dis_buf);
15051ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj         break;
15052ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj
15053e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
15054e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x80:
15055e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x81:
15056e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x82: /* JBb/JNAEb (jump below) */
15057e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x83: /* JNBb/JAEb (jump not below) */
15058e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x84: /* JZb/JEb (jump zero) */
15059e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x85: /* JNZb/JNEb (jump not zero) */
15060e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x86: /* JBEb/JNAb (jump below or equal) */
15061e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x87: /* JNBEb/JAb (jump not below or equal) */
15062e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x88: /* JSb (jump negative) */
15063e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x89: /* JSb (jump not negative) */
15064e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x8A: /* JP (jump parity even) */
15065e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x8B: /* JNP/JPO (jump parity odd) */
15066e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x8C: /* JLb/JNGEb (jump less) */
15067e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x8D: /* JGEb/JNLb (jump greater or equal) */
15068e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x8E: /* JLEb/JNGb (jump less or equal) */
15069e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x8F: /* JGb/JNLEb (jump greater) */
15070984d9b164dd17f07e603c41fe1e506e641e57d18sewardj       { Int    jmpDelta;
1507155085f8680acc89d727e321f3b34cae1a8c4093aflorian         const HChar* comment  = "";
15072984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         jmpDelta = (Int)getUDisp32(delta);
15073984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         d32 = (((Addr32)guest_EIP_bbstart)+delta+4) + jmpDelta;
15074e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj         delta += 4;
15075984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         if (resteerCisOk
15076984d9b164dd17f07e603c41fe1e506e641e57d18sewardj             && vex_control.guest_chase_cond
150770d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj             && (Addr32)d32 != (Addr32)guest_EIP_bbstart
15078984d9b164dd17f07e603c41fe1e506e641e57d18sewardj             && jmpDelta < 0
15079beac530a718fcc646bc61fe60a86f599df54e1d7florian             && resteerOkFn( callback_opaque, (Addr32)d32) ) {
15080984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            /* Speculation: assume this backward branch is taken.  So
15081984d9b164dd17f07e603c41fe1e506e641e57d18sewardj               we need to emit a side-exit to the insn following this
15082984d9b164dd17f07e603c41fe1e506e641e57d18sewardj               one, on the negation of the condition, and continue at
150830d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj               the branch target address (d32).  If we wind up back at
150840d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj               the first instruction of the trace, just stop; it's
150850d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj               better to let the IR loop unroller handle that case.*/
15086984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            stmt( IRStmt_Exit(
150870d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj                     mk_x86g_calculate_condition((X86Condcode)
150880d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj                                                 (1 ^ (opc - 0x80))),
15089984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                     Ijk_Boring,
15090c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     IRConst_U32(guest_EIP_bbstart+delta),
15091c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     OFFB_EIP ) );
15092984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            dres.whatNext   = Dis_ResteerC;
150930eaa35ff5569f09129073be27c2f827926f7010dflorian            dres.continueAt = (Addr32)d32;
15094984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            comment = "(assumed taken)";
15095984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         }
15096984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         else
15097984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         if (resteerCisOk
15098984d9b164dd17f07e603c41fe1e506e641e57d18sewardj             && vex_control.guest_chase_cond
150990d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj             && (Addr32)d32 != (Addr32)guest_EIP_bbstart
15100984d9b164dd17f07e603c41fe1e506e641e57d18sewardj             && jmpDelta >= 0
15101984d9b164dd17f07e603c41fe1e506e641e57d18sewardj             && resteerOkFn( callback_opaque,
15102beac530a718fcc646bc61fe60a86f599df54e1d7florian                             (Addr32)(guest_EIP_bbstart+delta)) ) {
15103984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            /* Speculation: assume this forward branch is not taken.
15104984d9b164dd17f07e603c41fe1e506e641e57d18sewardj               So we need to emit a side-exit to d32 (the dest) and
15105984d9b164dd17f07e603c41fe1e506e641e57d18sewardj               continue disassembling at the insn immediately
15106984d9b164dd17f07e603c41fe1e506e641e57d18sewardj               following this one. */
15107984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            stmt( IRStmt_Exit(
15108984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                     mk_x86g_calculate_condition((X86Condcode)(opc - 0x80)),
15109984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                     Ijk_Boring,
15110c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     IRConst_U32(d32),
15111c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     OFFB_EIP ) );
15112984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            dres.whatNext   = Dis_ResteerC;
151130eaa35ff5569f09129073be27c2f827926f7010dflorian            dres.continueAt = guest_EIP_bbstart + delta;
15114984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            comment = "(assumed not taken)";
15115984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         }
15116984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         else {
15117984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            /* Conservative default translation - end the block at
15118984d9b164dd17f07e603c41fe1e506e641e57d18sewardj               this point. */
15119c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jcc_01( &dres, (X86Condcode)(opc - 0x80),
15120984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                    (Addr32)(guest_EIP_bbstart+delta), d32);
15121c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres.whatNext == Dis_StopHere);
15122984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         }
15123984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         DIP("j%s-32 0x%x %s\n", name_X86Condcode(opc - 0x80), d32, comment);
15124e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj         break;
15125984d9b164dd17f07e603c41fe1e506e641e57d18sewardj       }
15126e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1512789cd09353a584000edaaa61558b27253bdea7452sewardj      /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
151284ed6429074bf94661586d751fbecac530f5e8156sewardj      case 0x31: { /* RDTSC */
151294ed6429074bf94661586d751fbecac530f5e8156sewardj         IRTemp   val  = newTemp(Ity_I64);
151304ed6429074bf94661586d751fbecac530f5e8156sewardj         IRExpr** args = mkIRExprVec_0();
151314ed6429074bf94661586d751fbecac530f5e8156sewardj         IRDirty* d    = unsafeIRDirty_1_N (
151324ed6429074bf94661586d751fbecac530f5e8156sewardj                            val,
151334ed6429074bf94661586d751fbecac530f5e8156sewardj                            0/*regparms*/,
151344ed6429074bf94661586d751fbecac530f5e8156sewardj                            "x86g_dirtyhelper_RDTSC",
151354ed6429074bf94661586d751fbecac530f5e8156sewardj                            &x86g_dirtyhelper_RDTSC,
151364ed6429074bf94661586d751fbecac530f5e8156sewardj                            args
151374ed6429074bf94661586d751fbecac530f5e8156sewardj                         );
15138a5cbbdc99afee50e9bcf1055fbc5b3e66dc1ecf3sewardj         /* execute the dirty call, dumping the result in val. */
15139a5cbbdc99afee50e9bcf1055fbc5b3e66dc1ecf3sewardj         stmt( IRStmt_Dirty(d) );
15140a5cbbdc99afee50e9bcf1055fbc5b3e66dc1ecf3sewardj         putIReg(4, R_EDX, unop(Iop_64HIto32, mkexpr(val)));
15141a5cbbdc99afee50e9bcf1055fbc5b3e66dc1ecf3sewardj         putIReg(4, R_EAX, unop(Iop_64to32, mkexpr(val)));
15142a5cbbdc99afee50e9bcf1055fbc5b3e66dc1ecf3sewardj         DIP("rdtsc\n");
15143a5cbbdc99afee50e9bcf1055fbc5b3e66dc1ecf3sewardj         break;
151444ed6429074bf94661586d751fbecac530f5e8156sewardj      }
1514577b86be374085943e902075b305ff047a053aac6sewardj
15146b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
15147b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
15148b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      case 0xA1: /* POP %FS */
15149b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj         dis_pop_segreg( R_FS, sz ); break;
15150b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      case 0xA9: /* POP %GS */
15151b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj         dis_pop_segreg( R_GS, sz ); break;
15152b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
15153b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      case 0xA0: /* PUSH %FS */
15154b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj         dis_push_segreg( R_FS, sz ); break;
15155b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      case 0xA8: /* PUSH %GS */
15156b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj         dis_push_segreg( R_GS, sz ); break;
15157b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
1515877b86be374085943e902075b305ff047a053aac6sewardj      /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
1515977b86be374085943e902075b305ff047a053aac6sewardj      case 0x90:
1516077b86be374085943e902075b305ff047a053aac6sewardj      case 0x91:
1516177b86be374085943e902075b305ff047a053aac6sewardj      case 0x92: /* set-Bb/set-NAEb (jump below) */
1516277b86be374085943e902075b305ff047a053aac6sewardj      case 0x93: /* set-NBb/set-AEb (jump not below) */
1516377b86be374085943e902075b305ff047a053aac6sewardj      case 0x94: /* set-Zb/set-Eb (jump zero) */
1516477b86be374085943e902075b305ff047a053aac6sewardj      case 0x95: /* set-NZb/set-NEb (jump not zero) */
1516577b86be374085943e902075b305ff047a053aac6sewardj      case 0x96: /* set-BEb/set-NAb (jump below or equal) */
1516677b86be374085943e902075b305ff047a053aac6sewardj      case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
1516777b86be374085943e902075b305ff047a053aac6sewardj      case 0x98: /* set-Sb (jump negative) */
1516877b86be374085943e902075b305ff047a053aac6sewardj      case 0x99: /* set-Sb (jump not negative) */
1516977b86be374085943e902075b305ff047a053aac6sewardj      case 0x9A: /* set-P (jump parity even) */
1517077b86be374085943e902075b305ff047a053aac6sewardj      case 0x9B: /* set-NP (jump parity odd) */
1517177b86be374085943e902075b305ff047a053aac6sewardj      case 0x9C: /* set-Lb/set-NGEb (jump less) */
1517277b86be374085943e902075b305ff047a053aac6sewardj      case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
1517377b86be374085943e902075b305ff047a053aac6sewardj      case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
1517477b86be374085943e902075b305ff047a053aac6sewardj      case 0x9F: /* set-Gb/set-NLEb (jump greater) */
151755bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         t1 = newTemp(Ity_I8);
151762a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
1517777b86be374085943e902075b305ff047a053aac6sewardj         modrm = getIByte(delta);
1517877b86be374085943e902075b305ff047a053aac6sewardj         if (epartIsReg(modrm)) {
1517977b86be374085943e902075b305ff047a053aac6sewardj            delta++;
151805bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            putIReg(1, eregOfRM(modrm), mkexpr(t1));
151812a9ad023890d3b34cf45e429df2a8ae88b419128sewardj            DIP("set%s %s\n", name_X86Condcode(opc-0x90),
1518277b86be374085943e902075b305ff047a053aac6sewardj                              nameIReg(1,eregOfRM(modrm)));
1518377b86be374085943e902075b305ff047a053aac6sewardj         } else {
15184750f407b6be1aac303964a219acf0a6de8b8c4dasewardj           addr = disAMode ( &alen, sorb, delta, dis_buf );
15185750f407b6be1aac303964a219acf0a6de8b8c4dasewardj           delta += alen;
15186750f407b6be1aac303964a219acf0a6de8b8c4dasewardj           storeLE( mkexpr(addr), mkexpr(t1) );
151872a9ad023890d3b34cf45e429df2a8ae88b419128sewardj           DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
1518877b86be374085943e902075b305ff047a053aac6sewardj         }
1518977b86be374085943e902075b305ff047a053aac6sewardj         break;
1519077b86be374085943e902075b305ff047a053aac6sewardj
15191180e8b39d5b4271e64634162986749c43536647csewardj      /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
15192180e8b39d5b4271e64634162986749c43536647csewardj
15193180e8b39d5b4271e64634162986749c43536647csewardj      case 0xA4: /* SHLDv imm8,Gv,Ev */
15194180e8b39d5b4271e64634162986749c43536647csewardj         modrm = getIByte(delta);
15195180e8b39d5b4271e64634162986749c43536647csewardj         d32   = delta + lengthAMode(delta);
151962d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj         vex_sprintf(dis_buf, "$%d", getIByte(d32));
15197180e8b39d5b4271e64634162986749c43536647csewardj         delta = dis_SHLRD_Gv_Ev (
15198180e8b39d5b4271e64634162986749c43536647csewardj                  sorb, delta, modrm, sz,
15199180e8b39d5b4271e64634162986749c43536647csewardj                  mkU8(getIByte(d32)), True, /* literal */
15200180e8b39d5b4271e64634162986749c43536647csewardj                  dis_buf, True );
15201180e8b39d5b4271e64634162986749c43536647csewardj         break;
15202a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      case 0xA5: /* SHLDv %cl,Gv,Ev */
15203a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj         modrm = getIByte(delta);
15204a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj         delta = dis_SHLRD_Gv_Ev (
15205a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                    sorb, delta, modrm, sz,
15206a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                    getIReg(1,R_ECX), False, /* not literal */
15207a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                    "%cl", True );
15208a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj         break;
15209a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
1521068511549b138ef55c8d31088cb0f20a72d83ab2bsewardj      case 0xAC: /* SHRDv imm8,Gv,Ev */
1521168511549b138ef55c8d31088cb0f20a72d83ab2bsewardj         modrm = getIByte(delta);
1521268511549b138ef55c8d31088cb0f20a72d83ab2bsewardj         d32   = delta + lengthAMode(delta);
152132d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj         vex_sprintf(dis_buf, "$%d", getIByte(d32));
1521468511549b138ef55c8d31088cb0f20a72d83ab2bsewardj         delta = dis_SHLRD_Gv_Ev (
1521568511549b138ef55c8d31088cb0f20a72d83ab2bsewardj                    sorb, delta, modrm, sz,
1521668511549b138ef55c8d31088cb0f20a72d83ab2bsewardj                    mkU8(getIByte(d32)), True, /* literal */
1521768511549b138ef55c8d31088cb0f20a72d83ab2bsewardj                    dis_buf, False );
1521868511549b138ef55c8d31088cb0f20a72d83ab2bsewardj         break;
15219a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj      case 0xAD: /* SHRDv %cl,Gv,Ev */
15220a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj         modrm = getIByte(delta);
15221a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj         delta = dis_SHLRD_Gv_Ev (
15222a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj                    sorb, delta, modrm, sz,
15223a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj                    getIReg(1,R_ECX), False, /* not literal */
15224a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj                    "%cl", False );
15225a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj         break;
15226a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj
15227f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj      /* =-=-=-=-=-=-=-=-=- SYSENTER -=-=-=-=-=-=-=-=-=-= */
15228f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj
15229f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj      case 0x34:
15230f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj         /* Simple implementation needing a long explaination.
15231f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj
15232f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            sysenter is a kind of syscall entry.  The key thing here
15233f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            is that the return address is not known -- that is
15234f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            something that is beyond Vex's knowledge.  So this IR
15235f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            forces a return to the scheduler, which can do what it
152364fa325af3891d57d174a025af2e6e8810a553660sewardj            likes to simulate the systenter, but it MUST set this
15237f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            thread's guest_EIP field with the continuation address
15238f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            before resuming execution.  If that doesn't happen, the
15239f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            thread will jump to address zero, which is probably
15240f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            fatal.
15241e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         */
15242e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj
15243e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         /* Note where we are, so we can back up the guest to this
15244e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj            point if the syscall needs to be restarted. */
15245e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
15246e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj                           mkU32(guest_EIP_curr_instr) ) );
15247c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jmp_lit(&dres, Ijk_Sys_sysenter, 0/*bogus next EIP value*/);
15248c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
15249f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj         DIP("sysenter");
15250f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj         break;
15251f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj
15252464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
15253464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
152540092e0d63a749778959b481a734dcbb3fb299766sewardj      case 0xC0: { /* XADD Gb,Eb */
152550092e0d63a749778959b481a734dcbb3fb299766sewardj         Bool decodeOK;
15256e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         delta = dis_xadd_G_E ( sorb, pfx_lock, 1, delta, &decodeOK );
152570092e0d63a749778959b481a734dcbb3fb299766sewardj         if (!decodeOK) goto decode_failure;
152580092e0d63a749778959b481a734dcbb3fb299766sewardj         break;
152590092e0d63a749778959b481a734dcbb3fb299766sewardj      }
152600092e0d63a749778959b481a734dcbb3fb299766sewardj      case 0xC1: { /* XADD Gv,Ev */
152610092e0d63a749778959b481a734dcbb3fb299766sewardj         Bool decodeOK;
15262e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         delta = dis_xadd_G_E ( sorb, pfx_lock, sz, delta, &decodeOK );
152630092e0d63a749778959b481a734dcbb3fb299766sewardj         if (!decodeOK) goto decode_failure;
15264883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj         break;
152650092e0d63a749778959b481a734dcbb3fb299766sewardj      }
15266883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
15267f13f37b9cc4219fa895526f34a5c2a45a8245cd3sewardj      /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
15268464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
152692b7a9208ee96939f12896085a143891160dc539asewardj      case 0x71:
152702b7a9208ee96939f12896085a143891160dc539asewardj      case 0x72:
1527138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
152722b7a9208ee96939f12896085a143891160dc539asewardj
152732b7a9208ee96939f12896085a143891160dc539asewardj      case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
152742b7a9208ee96939f12896085a143891160dc539asewardj      case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
15275464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
152762b7a9208ee96939f12896085a143891160dc539asewardj      case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
15277464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15278464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xFC:
15279464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xFD:
15280464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
15281464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15282464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xEC:
15283464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
15284464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15285464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xDC:
15286464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
15287464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15288464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xF8:
15289464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xF9:
15290464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
15291464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15292464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xE8:
15293464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
15294464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15295464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xD8:
15296464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
15297464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15298464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
15299464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
15300464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
153014340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
153024340dac5c2cede4962868e6da5b73282da2bc465sewardj
153034340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x74:
153044340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x75:
153054340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
153064340dac5c2cede4962868e6da5b73282da2bc465sewardj
153074340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x64:
153084340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x65:
153094340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
153104340dac5c2cede4962868e6da5b73282da2bc465sewardj
1531163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
1531263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
1531363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
1531463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
1531563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x68:
1531663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x69:
1531763ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
1531863ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
1531963ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x60:
1532063ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x61:
1532163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
1532263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
1532363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
1532463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
1532563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
1532663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
1532763ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
1532838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
153298d14a59858e2464baa217f19daff83562f3cdca0sewardj      case 0xF2:
1533038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF3:
153318d14a59858e2464baa217f19daff83562f3cdca0sewardj
1533238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
153338d14a59858e2464baa217f19daff83562f3cdca0sewardj      case 0xD2:
1533438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD3:
153358d14a59858e2464baa217f19daff83562f3cdca0sewardj
1533638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
1533738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE2:
15338464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      {
1533952d049186d07991237a825ec88aa7f1f303edb70sewardj         Int  delta0    = delta-1;
15340464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         Bool decode_OK = False;
1534138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
1534238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj         /* If sz==2 this is SSE, and we assume sse idec has
1534338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj            already spotted those cases by now. */
1534438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj         if (sz != 4)
1534538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj            goto decode_failure;
1534638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
15347464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
15348464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         if (!decode_OK) {
15349464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            delta = delta0;
15350464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            goto decode_failure;
15351464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         }
15352464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
15353464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      }
15354464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15355e3aa0163ce611325d11bedcd5e69dc3ae1adebe7tom      case 0x0E: /* FEMMS */
153568d14a59858e2464baa217f19daff83562f3cdca0sewardj      case 0x77: /* EMMS */
1535738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj         if (sz != 4)
1535838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj            goto decode_failure;
153594cb918d355cef4e7640d374346852db4556f3524sewardj         do_EMMS_preamble();
15360e3aa0163ce611325d11bedcd5e69dc3ae1adebe7tom         DIP("{f}emms\n");
153618d14a59858e2464baa217f19daff83562f3cdca0sewardj         break;
153628d14a59858e2464baa217f19daff83562f3cdca0sewardj
15363b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj      /* =-=-=-=-=-=-=-=-=- SGDT and SIDT =-=-=-=-=-=-=-=-=-=-= */
15364b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj      case 0x01: /* 0F 01 /0 -- SGDT */
15365b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                 /* 0F 01 /1 -- SIDT */
15366b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj      {
15367b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj          /* This is really revolting, but ... since each processor
15368b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj             (core) only has one IDT and one GDT, just let the guest
15369b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj             see it (pass-through semantics).  I can't see any way to
15370b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj             construct a faked-up value, so don't bother to try. */
15371b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         modrm = getUChar(delta);
15372b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         if (epartIsReg(modrm)) goto decode_failure;
15373b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         if (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)
15374b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj            goto decode_failure;
15375ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes         addr = disAMode ( &alen, sorb, delta, dis_buf );
15376ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes         delta += alen;
15377b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         switch (gregOfRM(modrm)) {
15378b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj            case 0: DIP("sgdt %s\n", dis_buf); break;
15379b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj            case 1: DIP("sidt %s\n", dis_buf); break;
15380b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj            default: vassert(0); /*NOTREACHED*/
15381b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         }
15382b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj
15383b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         IRDirty* d = unsafeIRDirty_0_N (
15384b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                          0/*regparms*/,
15385b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                          "x86g_dirtyhelper_SxDT",
15386b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                          &x86g_dirtyhelper_SxDT,
15387b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                          mkIRExprVec_2( mkexpr(addr),
15388b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                                         mkU32(gregOfRM(modrm)) )
15389b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                      );
15390b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         /* declare we're writing memory */
15391b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         d->mFx   = Ifx_Write;
15392b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         d->mAddr = mkexpr(addr);
15393b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         d->mSize = 6;
15394b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         stmt( IRStmt_Dirty(d) );
15395b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         break;
15396b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj      }
15397b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj
15398f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom      case 0x05: /* AMD's syscall */
15399f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
154003e5d82d003f0746010e22c7cfc4a25b34c9641f1sewardj                           mkU32(guest_EIP_curr_instr) ) );
15401f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom         jmp_lit(&dres, Ijk_Sys_syscall, ((Addr32)guest_EIP_bbstart)+delta);
15402f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom         vassert(dres.whatNext == Dis_StopHere);
15403f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom         DIP("syscall\n");
15404f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom         break;
15405f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom
15406e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
15407e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
15408e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      default:
15409e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj         goto decode_failure;
15410e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   } /* switch (opc) for the 2-byte opcodes */
15411e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   goto decode_success;
15412e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   } /* case 0x0F: of primary opcode */
15413c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
15414c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* ------------------------ ??? ------------------------ */
15415c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
15416c9a6570e86f4252f8a486b4df48de8710d357a4asewardj  default:
15417e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj  decode_failure:
15418c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* All decode failures end up here. */
15419442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj   if (sigill_diag) {
15420442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj      vex_printf("vex x86->IR: unhandled instruction bytes: "
15421442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj                 "0x%x 0x%x 0x%x 0x%x\n",
15422b173774421d015736c2316b5e6e998e7de545a5cflorian                 getIByte(delta_start+0),
15423b173774421d015736c2316b5e6e998e7de545a5cflorian                 getIByte(delta_start+1),
15424b173774421d015736c2316b5e6e998e7de545a5cflorian                 getIByte(delta_start+2),
15425b173774421d015736c2316b5e6e998e7de545a5cflorian                 getIByte(delta_start+3));
15426442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj   }
1542752444cb6696efd612ced78daa8feb235808ef165sewardj
15428b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   /* Tell the dispatcher that this insn cannot be decoded, and so has
15429b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      not been executed, and (is currently) the next to be executed.
15430b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      EIP should be up-to-date since it made so at the start of each
15431b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      insn, but nevertheless be paranoid and update it again right
15432b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      now. */
154339e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr) ) );
15434c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   jmp_lit(&dres, Ijk_NoDecode, guest_EIP_curr_instr);
15435c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres.whatNext == Dis_StopHere);
154369e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   dres.len = 0;
15437e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* We also need to say that a CAS is not expected now, regardless
15438e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      of what it might have been set to at the start of the function,
15439e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      since the IR that we've emitted just above (to synthesis a
15440e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      SIGILL) does not involve any CAS, and presumably no other IR has
15441e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      been emitted for this (non-decoded) insn. */
15442e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   *expect_CAS = False;
154439e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   return dres;
1544452444cb6696efd612ced78daa8feb235808ef165sewardj
15445c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   } /* switch (opc) for the main (primary) opcode switch. */
15446c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
15447e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj  decode_success:
15448c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* All decode successes end up here. */
15449c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   switch (dres.whatNext) {
15450c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      case Dis_Continue:
15451c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_bbstart + delta) ) );
15452c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         break;
15453c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      case Dis_ResteerU:
15454c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      case Dis_ResteerC:
15455c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         stmt( IRStmt_Put( OFFB_EIP, mkU32(dres.continueAt) ) );
15456c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         break;
15457c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      case Dis_StopHere:
15458c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         break;
15459c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      default:
15460c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(0);
15461c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   }
15462c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj
15463c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   DIP("\n");
154649e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   dres.len = delta - delta_start;
154659e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   return dres;
15466c9a6570e86f4252f8a486b4df48de8710d357a4asewardj}
15467c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
15468c9a6570e86f4252f8a486b4df48de8710d357a4asewardj#undef DIP
15469c9a6570e86f4252f8a486b4df48de8710d357a4asewardj#undef DIS
15470c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
154719e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
154729e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj/*------------------------------------------------------------*/
154739e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj/*--- Top-level fn                                         ---*/
154749e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj/*------------------------------------------------------------*/
154759e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
154769e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj/* Disassemble a single instruction into IR.  The instruction
154779e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   is located in host memory at &guest_code[delta]. */
154789e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
15479dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardjDisResult disInstr_X86 ( IRSB*        irsb_IN,
15480beac530a718fcc646bc61fe60a86f599df54e1d7florian                         Bool         (*resteerOkFn) ( void*, Addr ),
15481984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                         Bool         resteerCisOk,
15482c716aea1cafe66ee431dc7d6909c98f18788a028sewardj                         void*        callback_opaque,
154838462d113e3efeacceb304222dada8d85f748295aflorian                         const UChar* guest_code_IN,
154849e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj                         Long         delta,
15485d4cc0deec55ec0be1f2ac3b20f0d340265341f83florian                         Addr         guest_IP,
15486a5f55da7e956978fddad927436da5fab9568f3f1sewardj                         VexArch      guest_arch,
15487cacba8e675988fbf21b08feea1f317a9c896c053florian                         const VexArchInfo* archinfo,
15488cacba8e675988fbf21b08feea1f317a9c896c053florian                         const VexAbiInfo*  abiinfo,
154899b76916dcc1628e133d57db001563429c6e3a590sewardj                         VexEndness   host_endness_IN,
15490442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj                         Bool         sigill_diag_IN )
154919e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj{
15492e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   Int       i, x1, x2;
15493e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   Bool      expect_CAS, has_CAS;
154949e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   DisResult dres;
154959e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
154969e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   /* Set globals (see top of this file) */
15497a5f55da7e956978fddad927436da5fab9568f3f1sewardj   vassert(guest_arch == VexArchX86);
154989e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   guest_code           = guest_code_IN;
15499dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   irsb                 = irsb_IN;
155009b76916dcc1628e133d57db001563429c6e3a590sewardj   host_endness         = host_endness_IN;
155019e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   guest_EIP_curr_instr = (Addr32)guest_IP;
155029e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   guest_EIP_bbstart    = (Addr32)toUInt(guest_IP - delta);
155039e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
15504e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   x1 = irsb_IN->stmts_used;
15505e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   expect_CAS = False;
15506c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
15507984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                             resteerCisOk,
155080283430ee809d645864ddd2da5f450f88142b4cdsewardj                             callback_opaque,
15509442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj                             delta, archinfo, abiinfo, sigill_diag_IN );
15510e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   x2 = irsb_IN->stmts_used;
15511e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   vassert(x2 >= x1);
15512e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
15513e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* See comment at the top of disInstr_X86_WRK for meaning of
15514e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      expect_CAS.  Here, we (sanity-)check for the presence/absence of
15515e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      IRCAS as directed by the returned expect_CAS value. */
15516e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   has_CAS = False;
15517e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   for (i = x1; i < x2; i++) {
15518e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      if (irsb_IN->stmts[i]->tag == Ist_CAS)
15519e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         has_CAS = True;
15520e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
15521e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
15522e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   if (expect_CAS != has_CAS) {
15523e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* inconsistency detected.  re-disassemble the instruction so as
15524e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         to generate a useful error message; then assert. */
15525e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      vex_traceflags |= VEX_TRACE_FE;
15526c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
15527984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                                resteerCisOk,
155280283430ee809d645864ddd2da5f450f88142b4cdsewardj                                callback_opaque,
15529442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj                                delta, archinfo, abiinfo, sigill_diag_IN );
15530e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      for (i = x1; i < x2; i++) {
15531e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         vex_printf("\t\t");
15532e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         ppIRStmt(irsb_IN->stmts[i]);
15533e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         vex_printf("\n");
15534e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      }
15535e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* Failure of this assertion is serious and denotes a bug in
15536e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         disInstr. */
15537e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      vpanic("disInstr_X86: inconsistency in LOCK prefix handling");
15538e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
155399e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
155409e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   return dres;
155419e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj}
155429e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
155439e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
15544c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*--------------------------------------------------------------------*/
15545cef7d3e3df4796e35b4521158d9dc058f034aa87sewardj/*--- end                                         guest_x86_toIR.c ---*/
15546c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*--------------------------------------------------------------------*/
15547