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
1089ae8477745fd2a15453557d729a50e627325ee2sewardj   Copyright (C) 2004-2013 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:";
14127df596b1e36840e2d74c90aa55589934add61ccfsewardj      default: vpanic("sorbTxt(x86,guest)");
1413d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   }
1414d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
1415d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1416d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14177df596b1e36840e2d74c90aa55589934add61ccfsewardj/* 'virtual' is an IRExpr* holding a virtual address.  Convert it to a
14187df596b1e36840e2d74c90aa55589934add61ccfsewardj   linear address by adding any required segment override as indicated
14197df596b1e36840e2d74c90aa55589934add61ccfsewardj   by sorb. */
1420d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardjstatic
1421d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardjIRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1422d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
14233bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   Int    sreg;
14243bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   IRType hWordTy;
14253bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
1426d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1427d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   if (sorb == 0)
1428d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* the common case - no override */
1429d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      return virtual;
1430d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1431d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   switch (sorb) {
1432d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x3E: sreg = R_DS; break;
1433d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x26: sreg = R_ES; break;
1434d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x64: sreg = R_FS; break;
1435d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x65: sreg = R_GS; break;
14367df596b1e36840e2d74c90aa55589934add61ccfsewardj      default: vpanic("handleSegOverride(x86,guest)");
1437d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   }
1438d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14393bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
14407df596b1e36840e2d74c90aa55589934add61ccfsewardj
14413bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   seg_selector = newTemp(Ity_I32);
14423bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   ldt_ptr      = newTemp(hWordTy);
14433bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   gdt_ptr      = newTemp(hWordTy);
14443bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   r64          = newTemp(Ity_I64);
14457df596b1e36840e2d74c90aa55589934add61ccfsewardj
14463bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
14473bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
14483bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
1449d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14503bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   /*
14513bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   Call this to do the translation and limit checks:
14523bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
14533bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                                 UInt seg_selector, UInt virtual_addr )
14543bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   */
14553bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   assign(
14563bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj      r64,
14573bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj      mkIRExprCCall(
14583bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj         Ity_I64,
14593bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj         0/*regparms*/,
14603bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj         "x86g_use_seg_selector",
14613bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj         &x86g_use_seg_selector,
14623bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj         mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
14633bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                        mkexpr(seg_selector), virtual)
14643bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj      )
14653bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   );
1466d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
146752444cb6696efd612ced78daa8feb235808ef165sewardj   /* If the high 32 of the result are non-zero, there was a
146852444cb6696efd612ced78daa8feb235808ef165sewardj      failure in address translation.  In which case, make a
146952444cb6696efd612ced78daa8feb235808ef165sewardj      quick exit.
147052444cb6696efd612ced78daa8feb235808ef165sewardj   */
147152444cb6696efd612ced78daa8feb235808ef165sewardj   stmt(
147252444cb6696efd612ced78daa8feb235808ef165sewardj      IRStmt_Exit(
147352444cb6696efd612ced78daa8feb235808ef165sewardj         binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
147452444cb6696efd612ced78daa8feb235808ef165sewardj         Ijk_MapFail,
1475c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         IRConst_U32( guest_EIP_curr_instr ),
1476c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         OFFB_EIP
147752444cb6696efd612ced78daa8feb235808ef165sewardj      )
147852444cb6696efd612ced78daa8feb235808ef165sewardj   );
147952444cb6696efd612ced78daa8feb235808ef165sewardj
148052444cb6696efd612ced78daa8feb235808ef165sewardj   /* otherwise, here's the translated result. */
14813bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj   return unop(Iop_64to32, mkexpr(r64));
1482d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
1483d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1484d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1485d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/* Generate IR to calculate an address indicated by a ModRM and
1486d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   following SIB bytes.  The expression, and the number of bytes in
1487d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   the address mode, are returned.  Note that this fn should not be
1488d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   called if the R/M part of the address denotes a register instead of
1489d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   memory.  If print_codegen is true, text of the addressing mode is
1490940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   placed in buf.
1491940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
1492940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   The computed address is stored in a new tempreg, and the
1493940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   identity of the tempreg is returned.  */
1494940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
1495940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardjstatic IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1496940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj{
1497940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   IRTemp tmp = newTemp(Ity_I32);
1498940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   assign( tmp, addr32 );
1499940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   return tmp;
1500940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj}
1501d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1502d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardjstatic
150352d049186d07991237a825ec88aa7f1f303edb70sewardjIRTemp disAMode ( Int* len, UChar sorb, Int delta, HChar* buf )
1504d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
1505d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   UChar mod_reg_rm = getIByte(delta);
1506d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   delta++;
1507d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
15089ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj   buf[0] = (UChar)0;
15099ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj
1510d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1511d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      jump table seems a bit excessive.
1512d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   */
15139b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj   mod_reg_rm &= 0xC7;                      /* is now XX000YYY */
15149b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj   mod_reg_rm  = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
15159b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj                                            /* is now XX0XXYYY */
15169b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj   mod_reg_rm &= 0x1F;                      /* is now 000XXYYY */
1517d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   switch (mod_reg_rm) {
1518d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1519d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1520d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         --> GET %reg, t
1521d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      */
1522d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x00: case 0x01: case 0x02: case 0x03:
1523d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1524d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         { UChar rm = mod_reg_rm;
1525d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj           DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1526d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj           *len = 1;
15275bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj           return disAMode_copy2tmp(
1528940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                  handleSegOverride(sorb, getIReg(4,rm)));
1529d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1530d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1531d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* d8(%eax) ... d8(%edi), not including d8(%esp)
1532d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         --> GET %reg, t ; ADDL d8, t
1533d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      */
1534d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x08: case 0x09: case 0x0A: case 0x0B:
1535d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
15369b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         { UChar rm = toUChar(mod_reg_rm & 7);
1537d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj           UInt  d  = getSDisp8(delta);
15382d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj           DIS(buf, "%s%d(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
15395bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj           *len = 2;
15405bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj           return disAMode_copy2tmp(
1541940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                  handleSegOverride(sorb,
1542940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                     binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
1543d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1544d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1545d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* d32(%eax) ... d32(%edi), not including d32(%esp)
1546d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         --> GET %reg, t ; ADDL d8, t
1547d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      */
1548d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x10: case 0x11: case 0x12: case 0x13:
1549d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* ! 14 */ case 0x15: case 0x16: case 0x17:
15509b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         { UChar rm = toUChar(mod_reg_rm & 7);
1551d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj           UInt  d  = getUDisp32(delta);
15522d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj           DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
15535bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj           *len = 5;
15545bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj           return disAMode_copy2tmp(
1555940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                  handleSegOverride(sorb,
1556940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                     binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
1557d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1558d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1559d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* a register, %eax .. %edi.  This shouldn't happen. */
1560d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x18: case 0x19: case 0x1A: case 0x1B:
1561d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1562d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         vpanic("disAMode(x86): not an addr!");
1563d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1564d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* a 32-bit literal address
1565d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         --> MOV d32, tmp
1566d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      */
1567d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x05:
1568d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         { UInt d = getUDisp32(delta);
1569d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj           *len = 5;
1570d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj           DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
1571940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj           return disAMode_copy2tmp(
1572940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                     handleSegOverride(sorb, mkU32(d)));
1573d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1574d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1575d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x04: {
1576d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         /* SIB, with no displacement.  Special cases:
1577d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            -- %esp cannot act as an index value.
1578d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               If index_r indicates %esp, zero is used for the index.
1579d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            -- when mod is zero and base indicates EBP, base is instead
1580d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               a 32-bit literal.
1581d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            It's all madness, I tell you.  Extract %index, %base and
1582d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            scale from the SIB byte.  The value denoted is then:
1583d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               | %index == %ESP && %base == %EBP
1584d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               = d32 following SIB byte
1585d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               | %index == %ESP && %base != %EBP
1586d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               = %base
1587d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               | %index != %ESP && %base == %EBP
1588d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               = d32 following SIB byte + (%index << scale)
1589d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               | %index != %ESP && %base != %ESP
1590d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               = %base + (%index << scale)
1591d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1592d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            What happens to the souls of CPU architects who dream up such
1593d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            horrendous schemes, do you suppose?
1594d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         */
1595d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         UChar sib     = getIByte(delta);
15969b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar scale   = toUChar((sib >> 6) & 3);
15979b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar index_r = toUChar((sib >> 3) & 7);
15989b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar base_r  = toUChar(sib & 7);
15995bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         delta++;
1600d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1601d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (index_r != R_ESP && base_r != R_EBP) {
1602d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1603d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                      nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
16045bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 2;
1605940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            return
1606940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj               disAMode_copy2tmp(
16075bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               handleSegOverride(sorb,
16085bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                  binop(Iop_Add32,
1609d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                        getIReg(4,base_r),
1610d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                        binop(Iop_Shl32, getIReg(4,index_r),
16116d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj                              mkU8(scale)))));
1612d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1613d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1614d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (index_r != R_ESP && base_r == R_EBP) {
1615d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            UInt d = getUDisp32(delta);
1616d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1617d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                      nameIReg(4,index_r), 1<<scale);
1618d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            *len = 6;
1619d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            return
1620940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj               disAMode_copy2tmp(
1621d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj               handleSegOverride(sorb,
16225bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                  binop(Iop_Add32,
16235bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                        binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
1624940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                        mkU32(d))));
1625d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1626d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1627d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (index_r == R_ESP && base_r != R_EBP) {
1628d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
16295bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 2;
16305bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            return disAMode_copy2tmp(
1631940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                   handleSegOverride(sorb, getIReg(4,base_r)));
1632d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1633d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1634d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (index_r == R_ESP && base_r == R_EBP) {
1635d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            UInt d = getUDisp32(delta);
16369c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj            DIS(buf, "%s0x%x(,,)", sorbTxt(sorb), d);
16375bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 6;
16385bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            return disAMode_copy2tmp(
1639940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                   handleSegOverride(sorb, mkU32(d)));
1640d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1641ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj         /*NOTREACHED*/
1642d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         vassert(0);
1643d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      }
1644d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1645d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* SIB, with 8-bit displacement.  Special cases:
1646d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         -- %esp cannot act as an index value.
1647d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            If index_r indicates %esp, zero is used for the index.
1648d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         Denoted value is:
1649d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            | %index == %ESP
1650d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            = d8 + %base
1651d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            | %index != %ESP
1652d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            = d8 + %base + (%index << scale)
1653d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      */
1654d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x0C: {
1655d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         UChar sib     = getIByte(delta);
16569b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar scale   = toUChar((sib >> 6) & 3);
16579b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar index_r = toUChar((sib >> 3) & 7);
16589b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar base_r  = toUChar(sib & 7);
1659d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         UInt  d       = getSDisp8(delta+1);
1660d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1661d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (index_r == R_ESP) {
16622d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj            DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
16632d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj                                   (Int)d, nameIReg(4,base_r));
16645bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 3;
16655bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            return disAMode_copy2tmp(
1666940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                   handleSegOverride(sorb,
1667940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                      binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
1668d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         } else {
16692d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj            DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1670d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                     nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
16715bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 3;
16725bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            return
1673940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                disAMode_copy2tmp(
1674940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                handleSegOverride(sorb,
167577b86be374085943e902075b305ff047a053aac6sewardj                  binop(Iop_Add32,
167677b86be374085943e902075b305ff047a053aac6sewardj                        binop(Iop_Add32,
167777b86be374085943e902075b305ff047a053aac6sewardj                              getIReg(4,base_r),
167877b86be374085943e902075b305ff047a053aac6sewardj                              binop(Iop_Shl32,
16796d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj                                    getIReg(4,index_r), mkU8(scale))),
1680940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                        mkU32(d))));
1681d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1682ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj	 /*NOTREACHED*/
1683d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         vassert(0);
1684d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      }
1685d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1686d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* SIB, with 32-bit displacement.  Special cases:
1687d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         -- %esp cannot act as an index value.
1688d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            If index_r indicates %esp, zero is used for the index.
1689d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         Denoted value is:
1690d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            | %index == %ESP
1691d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            = d32 + %base
1692d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            | %index != %ESP
1693d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            = d32 + %base + (%index << scale)
1694d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      */
1695d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x14: {
1696d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         UChar sib     = getIByte(delta);
16979b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar scale   = toUChar((sib >> 6) & 3);
16989b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar index_r = toUChar((sib >> 3) & 7);
16999b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar base_r  = toUChar(sib & 7);
1700d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         UInt d        = getUDisp32(delta+1);
1701d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1702d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (index_r == R_ESP) {
17032d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj            DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
17042d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj                                   (Int)d, nameIReg(4,base_r));
17055bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 6;
17065bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            return disAMode_copy2tmp(
1707940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                   handleSegOverride(sorb,
1708940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                      binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
1709d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         } else {
17102d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj            DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
17112d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj                     nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
17125bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            *len = 6;
17135bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            return
1714940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                disAMode_copy2tmp(
1715940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                handleSegOverride(sorb,
17169334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                  binop(Iop_Add32,
17179334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                        binop(Iop_Add32,
17189334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                              getIReg(4,base_r),
17199334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                              binop(Iop_Shl32,
17206d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj                                    getIReg(4,index_r), mkU8(scale))),
1721940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                        mkU32(d))));
1722d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         }
1723ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj	 /*NOTREACHED*/
1724d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         vassert(0);
1725d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      }
1726d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1727d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      default:
1728d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         vpanic("disAMode(x86)");
1729d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         return 0; /*notreached*/
1730d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   }
1731d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
1732d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1733d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1734d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/* Figure out the number of (insn-stream) bytes constituting the amode
1735d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   beginning at delta.  Is useful for getting hold of literals beyond
1736d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   the end of the amode before it has been disassembled.  */
1737d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
173852d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt lengthAMode ( Int delta )
1739d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj{
1740d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   UChar mod_reg_rm = getIByte(delta); delta++;
1741d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1742d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1743d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      jump table seems a bit excessive.
1744d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   */
1745d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   mod_reg_rm &= 0xC7;               /* is now XX000YYY */
17469b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj   mod_reg_rm  = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
17479b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj                                     /* is now XX0XXYYY */
1748d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   mod_reg_rm &= 0x1F;               /* is now 000XXYYY */
1749d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   switch (mod_reg_rm) {
1750d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1751d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1752d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x00: case 0x01: case 0x02: case 0x03:
1753d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1754d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         return 1;
1755d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1756d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1757d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x08: case 0x09: case 0x0A: case 0x0B:
1758d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1759d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         return 2;
1760d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1761d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1762d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x10: case 0x11: case 0x12: case 0x13:
1763d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* ! 14 */ case 0x15: case 0x16: case 0x17:
1764d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         return 5;
1765d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1766d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* a register, %eax .. %edi.  (Not an addr, but still handled.) */
1767d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x18: case 0x19: case 0x1A: case 0x1B:
1768d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1769d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         return 1;
1770d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1771d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* a 32-bit literal address. */
1772d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x05: return 5;
1773d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1774d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* SIB, no displacement.  */
1775d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x04: {
1776d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         UChar sib    = getIByte(delta);
17779b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         UChar base_r = toUChar(sib & 7);
1778d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         if (base_r == R_EBP) return 6; else return 2;
1779d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      }
1780d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* SIB, with 8-bit displacement.  */
1781d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x0C: return 3;
1782d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1783d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* SIB, with 32-bit displacement.  */
1784d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      case 0x14: return 6;
1785d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1786d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      default:
1787d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         vpanic("lengthAMode");
1788d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         return 0; /*notreached*/
1789d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   }
1790d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj}
1791d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
1792d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/*------------------------------------------------------------*/
1793d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/*--- Disassembling common idioms                          ---*/
1794d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj/*------------------------------------------------------------*/
1795c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
1796e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj/* Handle binary integer instructions of the form
1797e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      op E, G  meaning
1798e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      op reg-or-mem, reg
1799e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   Is passed the a ptr to the modRM byte, the actual operation, and the
1800e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   data size.  Returns the address advanced completely over this
1801e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   instruction.
1802e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1803e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   E(src) is reg-or-mem
1804e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   G(dst) is reg.
1805e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1806e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   If E is reg, -->    GET %G,  tmp
1807e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       OP %E,   tmp
1808e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       PUT tmp, %G
1809e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1810e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   If E is mem and OP is not reversible,
1811e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                -->    (getAddr E) -> tmpa
1812e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       LD (tmpa), tmpa
1813e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       GET %G, tmp2
1814e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       OP tmpa, tmp2
1815e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       PUT tmp2, %G
1816e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1817e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   If E is mem and OP is reversible
1818e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                -->    (getAddr E) -> tmpa
1819e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       LD (tmpa), tmpa
1820e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       OP %G, tmpa
1821e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                       PUT tmpa, %G
1822e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj*/
1823e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardjstatic
1824e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardjUInt dis_op2_E_G ( UChar       sorb,
1825180e8b39d5b4271e64634162986749c43536647csewardj                   Bool        addSubCarry,
1826e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                   IROp        op8,
1827e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                   Bool        keep,
1828e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                   Int         size,
182952d049186d07991237a825ec88aa7f1f303edb70sewardj                   Int         delta0,
183055085f8680acc89d727e321f3b34cae1a8c4093aflorian                   const HChar* t_x86opc )
1831e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj{
1832c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar   dis_buf[50];
18339334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   Int     len;
1834e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   IRType  ty   = szToITy(size);
1835e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   IRTemp  dst1 = newTemp(ty);
1836e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   IRTemp  src  = newTemp(ty);
1837e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   IRTemp  dst0 = newTemp(ty);
1838e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   UChar   rm   = getUChar(delta0);
183992d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp  addr = IRTemp_INVALID;
1840e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1841180e8b39d5b4271e64634162986749c43536647csewardj   /* addSubCarry == True indicates the intended operation is
1842180e8b39d5b4271e64634162986749c43536647csewardj      add-with-carry or subtract-with-borrow. */
1843180e8b39d5b4271e64634162986749c43536647csewardj   if (addSubCarry) {
1844180e8b39d5b4271e64634162986749c43536647csewardj      vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1845180e8b39d5b4271e64634162986749c43536647csewardj      vassert(keep);
1846180e8b39d5b4271e64634162986749c43536647csewardj   }
1847180e8b39d5b4271e64634162986749c43536647csewardj
1848e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   if (epartIsReg(rm)) {
1849e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      /* Specially handle XOR reg,reg, because that doesn't really
1850e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj         depend on reg, and doing the obvious thing potentially
1851e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj         generates a spurious value check failure due to the bogus
185255efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj         dependency.  Ditto SBB reg,reg. */
185355efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj      if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
185455efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj          && gregOfRM(rm) == eregOfRM(rm)) {
185555efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj         putIReg(size, gregOfRM(rm), mkU(ty,0));
1856e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      }
1857e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      assign( dst0, getIReg(size,gregOfRM(rm)) );
1858e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      assign( src,  getIReg(size,eregOfRM(rm)) );
1859e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1860180e8b39d5b4271e64634162986749c43536647csewardj      if (addSubCarry && op8 == Iop_Add8) {
1861e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_ADC( size, dst1, dst0, src,
1862e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1863e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1864180e8b39d5b4271e64634162986749c43536647csewardj      } else
1865180e8b39d5b4271e64634162986749c43536647csewardj      if (addSubCarry && op8 == Iop_Sub8) {
1866e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_SBB( size, dst1, dst0, src,
1867e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1868180e8b39d5b4271e64634162986749c43536647csewardj         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1869180e8b39d5b4271e64634162986749c43536647csewardj      } else {
1870180e8b39d5b4271e64634162986749c43536647csewardj         assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
18715bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         if (isAddSub(op8))
18722a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(op8, dst0, src, ty);
1873b9c5cf639b3b21b972599d27207a033afc76ef67sewardj         else
18742a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1(op8, dst1, ty);
1875180e8b39d5b4271e64634162986749c43536647csewardj         if (keep)
1876180e8b39d5b4271e64634162986749c43536647csewardj            putIReg(size, gregOfRM(rm), mkexpr(dst1));
1877180e8b39d5b4271e64634162986749c43536647csewardj      }
1878e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1879e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1880e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                          nameIReg(size,eregOfRM(rm)),
1881e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                          nameIReg(size,gregOfRM(rm)));
1882e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      return 1+delta0;
1883e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   } else {
18849334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      /* E refers to memory */
18859334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      addr = disAMode ( &len, sorb, delta0, dis_buf);
18869334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      assign( dst0, getIReg(size,gregOfRM(rm)) );
1887940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      assign( src,  loadLE(szToITy(size), mkexpr(addr)) );
18889334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
1889180e8b39d5b4271e64634162986749c43536647csewardj      if (addSubCarry && op8 == Iop_Add8) {
1890e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_ADC( size, dst1, dst0, src,
1891e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1892180e8b39d5b4271e64634162986749c43536647csewardj         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1893180e8b39d5b4271e64634162986749c43536647csewardj      } else
1894180e8b39d5b4271e64634162986749c43536647csewardj      if (addSubCarry && op8 == Iop_Sub8) {
1895e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_SBB( size, dst1, dst0, src,
1896e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
18979334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj         putIReg(size, gregOfRM(rm), mkexpr(dst1));
1898180e8b39d5b4271e64634162986749c43536647csewardj      } else {
1899180e8b39d5b4271e64634162986749c43536647csewardj         assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
19005bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         if (isAddSub(op8))
19012a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(op8, dst0, src, ty);
1902b9c5cf639b3b21b972599d27207a033afc76ef67sewardj         else
19032a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1(op8, dst1, ty);
1904180e8b39d5b4271e64634162986749c43536647csewardj         if (keep)
1905180e8b39d5b4271e64634162986749c43536647csewardj            putIReg(size, gregOfRM(rm), mkexpr(dst1));
1906180e8b39d5b4271e64634162986749c43536647csewardj      }
19079334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
1908e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1909e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj                          dis_buf,nameIReg(size,gregOfRM(rm)));
19109334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      return len+delta0;
1911e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   }
1912e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj}
1913e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1914e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1915e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1916e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj/* Handle binary integer instructions of the form
1917e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      op G, E  meaning
1918e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      op reg, reg-or-mem
1919e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   Is passed the a ptr to the modRM byte, the actual operation, and the
1920e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   data size.  Returns the address advanced completely over this
1921e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   instruction.
1922e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1923e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   G(src) is reg.
1924e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   E(dst) is reg-or-mem
1925e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1926e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   If E is reg, -->    GET %E,  tmp
1927e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       OP %G,   tmp
1928e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       PUT tmp, %E
1929e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1930e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   If E is mem, -->    (getAddr E) -> tmpa
1931e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       LD (tmpa), tmpv
1932e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       OP %G, tmpv
1933e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       ST tmpv, (tmpa)
1934e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj*/
1935e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjstatic
1936e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjUInt dis_op2_G_E ( UChar       sorb,
1937e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                   Bool        locked,
1938caca9d0d3729c36af6ae02b0654cb289101248cbsewardj                   Bool        addSubCarry,
1939e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                   IROp        op8,
1940e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                   Bool        keep,
1941e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                   Int         size,
194252d049186d07991237a825ec88aa7f1f303edb70sewardj                   Int         delta0,
194355085f8680acc89d727e321f3b34cae1a8c4093aflorian                   const HChar* t_x86opc )
1944e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj{
1945c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar   dis_buf[50];
1946e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   Int     len;
1947e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRType  ty   = szToITy(size);
1948e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRTemp  dst1 = newTemp(ty);
1949e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRTemp  src  = newTemp(ty);
1950e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRTemp  dst0 = newTemp(ty);
1951e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   UChar   rm   = getIByte(delta0);
195292d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp  addr = IRTemp_INVALID;
1953e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1954caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   /* addSubCarry == True indicates the intended operation is
1955caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      add-with-carry or subtract-with-borrow. */
1956caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   if (addSubCarry) {
1957caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1958caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      vassert(keep);
1959caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   }
1960caca9d0d3729c36af6ae02b0654cb289101248cbsewardj
1961e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   if (epartIsReg(rm)) {
1962e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      /* Specially handle XOR reg,reg, because that doesn't really
1963e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj         depend on reg, and doing the obvious thing potentially
1964e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj         generates a spurious value check failure due to the bogus
196555efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj         dependency.  Ditto SBB reg,reg.*/
196655efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj      if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
196755efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj          && gregOfRM(rm) == eregOfRM(rm)) {
196855efbdfb2fef807fbba2c20825b6e2a77cea7504sewardj         putIReg(size, eregOfRM(rm), mkU(ty,0));
1969e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      }
1970e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      assign(dst0, getIReg(size,eregOfRM(rm)));
1971e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      assign(src,  getIReg(size,gregOfRM(rm)));
1972e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1973caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      if (addSubCarry && op8 == Iop_Add8) {
1974e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_ADC( size, dst1, dst0, src,
1975e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
19761813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         putIReg(size, eregOfRM(rm), mkexpr(dst1));
1977caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      } else
1978caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      if (addSubCarry && op8 == Iop_Sub8) {
1979e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_SBB( size, dst1, dst0, src,
1980e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
1981e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj         putIReg(size, eregOfRM(rm), mkexpr(dst1));
1982caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      } else {
1983caca9d0d3729c36af6ae02b0654cb289101248cbsewardj         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
19845bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         if (isAddSub(op8))
19852a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(op8, dst0, src, ty);
1986b9c5cf639b3b21b972599d27207a033afc76ef67sewardj         else
19872a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1(op8, dst1, ty);
1988caca9d0d3729c36af6ae02b0654cb289101248cbsewardj         if (keep)
1989caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            putIReg(size, eregOfRM(rm), mkexpr(dst1));
1990caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      }
1991e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1992e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1993e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                          nameIReg(size,gregOfRM(rm)),
1994e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                          nameIReg(size,eregOfRM(rm)));
1995e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      return 1+delta0;
1996e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   }
1997e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
1998e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   /* E refers to memory */
1999e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   {
2000e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      addr = disAMode ( &len, sorb, delta0, dis_buf);
2001940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      assign(dst0, loadLE(ty,mkexpr(addr)));
2002e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      assign(src,  getIReg(size,gregOfRM(rm)));
2003e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
2004caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      if (addSubCarry && op8 == Iop_Add8) {
2005e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (locked) {
2006e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* cas-style store */
2007e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_ADC( size, dst1, dst0, src,
2008e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                        /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2009e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         } else {
2010e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* normal store */
2011e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_ADC( size, dst1, dst0, src,
2012e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                        /*store*/addr, IRTemp_INVALID, 0 );
2013e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
2014caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      } else
2015caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      if (addSubCarry && op8 == Iop_Sub8) {
2016e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (locked) {
2017e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* cas-style store */
2018e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_SBB( size, dst1, dst0, src,
2019e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                        /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2020e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         } else {
2021e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* normal store */
2022e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_SBB( size, dst1, dst0, src,
2023e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                        /*store*/addr, IRTemp_INVALID, 0 );
2024e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
2025caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      } else {
2026caca9d0d3729c36af6ae02b0654cb289101248cbsewardj         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2027e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (keep) {
2028e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
2029e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (0) vex_printf("locked case\n" );
2030e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr),
2031e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                      mkexpr(dst0)/*expval*/,
2032e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                      mkexpr(dst1)/*newval*/, guest_EIP_curr_instr );
2033e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
2034e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (0) vex_printf("nonlocked case\n");
2035e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE(mkexpr(addr), mkexpr(dst1));
2036e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
2037e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
20385bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         if (isAddSub(op8))
20392a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2040b9c5cf639b3b21b972599d27207a033afc76ef67sewardj         else
20412a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1(op8, dst1, ty);
2042caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      }
2043e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2044e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2045e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                          nameIReg(size,gregOfRM(rm)), dis_buf);
2046e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      return len+delta0;
2047e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   }
2048e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj}
2049e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2050e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2051e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj/* Handle move instructions of the form
2052e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      mov E, G  meaning
2053e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      mov reg-or-mem, reg
2054e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   Is passed the a ptr to the modRM byte, and the data size.  Returns
2055e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   the address advanced completely over this instruction.
2056e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2057e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   E(src) is reg-or-mem
2058e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   G(dst) is reg.
2059e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2060e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   If E is reg, -->    GET %E,  tmpv
2061e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       PUT tmpv, %G
2062e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2063e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   If E is mem  -->    (getAddr E) -> tmpa
2064e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       LD (tmpa), tmpb
2065e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       PUT tmpb, %G
2066e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj*/
2067e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjstatic
2068e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjUInt dis_mov_E_G ( UChar       sorb,
2069e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                   Int         size,
207052d049186d07991237a825ec88aa7f1f303edb70sewardj                   Int         delta0 )
2071e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj{
2072e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   Int len;
2073e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   UChar rm = getIByte(delta0);
2074c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
2075e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2076e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   if (epartIsReg(rm)) {
20777ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj      putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
2078e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      DIP("mov%c %s,%s\n", nameISize(size),
2079e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                           nameIReg(size,eregOfRM(rm)),
2080e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                           nameIReg(size,gregOfRM(rm)));
20817ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj      return 1+delta0;
2082e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   }
2083e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2084e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   /* E refers to memory */
2085e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   {
2086940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
2087940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
2088e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      DIP("mov%c %s,%s\n", nameISize(size),
2089e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                           dis_buf,nameIReg(size,gregOfRM(rm)));
2090e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      return delta0+len;
2091e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   }
2092e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj}
2093e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2094e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2095e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj/* Handle move instructions of the form
2096e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      mov G, E  meaning
2097e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      mov reg, reg-or-mem
2098e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   Is passed the a ptr to the modRM byte, and the data size.  Returns
2099e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   the address advanced completely over this instruction.
2100e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2101e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   G(src) is reg.
2102e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   E(dst) is reg-or-mem
2103e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2104e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   If E is reg, -->    GET %G,  tmp
2105e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       PUT tmp, %E
2106e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
2107e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   If E is mem, -->    (getAddr E) -> tmpa
2108e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       GET %G, tmpv
2109e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                       ST tmpv, (tmpa)
2110e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj*/
2111c9a6570e86f4252f8a486b4df48de8710d357a4asewardjstatic
2112c9a6570e86f4252f8a486b4df48de8710d357a4asewardjUInt dis_mov_G_E ( UChar       sorb,
2113c9a6570e86f4252f8a486b4df48de8710d357a4asewardj                   Int         size,
211452d049186d07991237a825ec88aa7f1f303edb70sewardj                   Int         delta0 )
2115c9a6570e86f4252f8a486b4df48de8710d357a4asewardj{
2116e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   Int len;
2117c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   UChar rm = getIByte(delta0);
2118c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
2119c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
2120c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   if (epartIsReg(rm)) {
212141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
2122c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      DIP("mov%c %s,%s\n", nameISize(size),
2123c9a6570e86f4252f8a486b4df48de8710d357a4asewardj                           nameIReg(size,gregOfRM(rm)),
2124c9a6570e86f4252f8a486b4df48de8710d357a4asewardj                           nameIReg(size,eregOfRM(rm)));
2125c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      return 1+delta0;
2126c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   }
2127c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
2128c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* E refers to memory */
2129c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   {
2130940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
2131940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
2132c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      DIP("mov%c %s,%s\n", nameISize(size),
2133c9a6570e86f4252f8a486b4df48de8710d357a4asewardj                           nameIReg(size,gregOfRM(rm)), dis_buf);
2134e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      return len+delta0;
2135c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   }
2136c9a6570e86f4252f8a486b4df48de8710d357a4asewardj}
2137c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
2138c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
21390611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj/* op $immediate, AL/AX/EAX. */
21400611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardjstatic
21410611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardjUInt dis_op_imm_A ( Int    size,
2142a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj                    Bool   carrying,
21430611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                    IROp   op8,
21440611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                    Bool   keep,
214552d049186d07991237a825ec88aa7f1f303edb70sewardj                    Int    delta,
214655085f8680acc89d727e321f3b34cae1a8c4093aflorian                    const HChar* t_x86opc )
21470611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj{
21480611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   IRType ty   = szToITy(size);
21490611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   IRTemp dst0 = newTemp(ty);
21500611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   IRTemp src  = newTemp(ty);
21510611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   IRTemp dst1 = newTemp(ty);
21520611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   UInt lit    = getUDisp(size,delta);
21530611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   assign(dst0, getIReg(size,R_EAX));
21540611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   assign(src,  mkU(ty,lit));
2155a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj
2156a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   if (isAddSub(op8) && !carrying) {
2157a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
21582a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      setFlags_DEP1_DEP2(op8, dst0, src, ty);
2159a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   }
2160b9c5cf639b3b21b972599d27207a033afc76ef67sewardj   else
2161a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   if (isLogic(op8)) {
2162a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      vassert(!carrying);
2163a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
21642a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      setFlags_DEP1(op8, dst1, ty);
2165a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   }
2166a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   else
2167a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   if (op8 == Iop_Add8 && carrying) {
2168e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      helper_ADC( size, dst1, dst0, src,
2169e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2170a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   }
21712a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   else
21722fbae083dad486e8e623011b4dd68ba204c2a228sewardj   if (op8 == Iop_Sub8 && carrying) {
2173e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      helper_SBB( size, dst1, dst0, src,
2174e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
21752fbae083dad486e8e623011b4dd68ba204c2a228sewardj   }
21762fbae083dad486e8e623011b4dd68ba204c2a228sewardj   else
21772a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      vpanic("dis_op_imm_A(x86,guest)");
21780611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
21790611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   if (keep)
21800611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      putIReg(size, R_EAX, mkexpr(dst1));
21810611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
21820611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
21830611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                           lit, nameIReg(size,R_EAX));
21840611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   return delta+size;
21850611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj}
21869334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
21879334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
21889334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj/* Sign- and Zero-extending moves. */
21899334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardjstatic
219052d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_movx_E_G ( UChar      sorb,
219152d049186d07991237a825ec88aa7f1f303edb70sewardj                    Int delta, Int szs, Int szd, Bool sign_extend )
21929334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj{
21939334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   UChar rm = getIByte(delta);
21949334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   if (epartIsReg(rm)) {
219533ca4acf01e29bf8ec4adce63aa5925d549c105esewardj      if (szd == szs) {
219633ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         // mutant case.  See #250799
219733ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         putIReg(szd, gregOfRM(rm),
219833ca4acf01e29bf8ec4adce63aa5925d549c105esewardj                           getIReg(szs,eregOfRM(rm)));
219933ca4acf01e29bf8ec4adce63aa5925d549c105esewardj      } else {
220033ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         // normal case
220133ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         putIReg(szd, gregOfRM(rm),
220233ca4acf01e29bf8ec4adce63aa5925d549c105esewardj                      unop(mkWidenOp(szs,szd,sign_extend),
220333ca4acf01e29bf8ec4adce63aa5925d549c105esewardj                           getIReg(szs,eregOfRM(rm))));
220433ca4acf01e29bf8ec4adce63aa5925d549c105esewardj      }
22059334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
22069334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                               nameISize(szs), nameISize(szd),
22079334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                               nameIReg(szs,eregOfRM(rm)),
22089334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                               nameIReg(szd,gregOfRM(rm)));
22099334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      return 1+delta;
22109334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   }
22119334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
22129334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   /* E refers to memory */
22139334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   {
2214940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      Int    len;
2215c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      HChar  dis_buf[50];
2216940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
221733ca4acf01e29bf8ec4adce63aa5925d549c105esewardj      if (szd == szs) {
221833ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         // mutant case.  See #250799
221933ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         putIReg(szd, gregOfRM(rm),
222033ca4acf01e29bf8ec4adce63aa5925d549c105esewardj                           loadLE(szToITy(szs),mkexpr(addr)));
222133ca4acf01e29bf8ec4adce63aa5925d549c105esewardj      } else {
222233ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         // normal case
222333ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         putIReg(szd, gregOfRM(rm),
222433ca4acf01e29bf8ec4adce63aa5925d549c105esewardj                      unop(mkWidenOp(szs,szd,sign_extend),
222533ca4acf01e29bf8ec4adce63aa5925d549c105esewardj                           loadLE(szToITy(szs),mkexpr(addr))));
222633ca4acf01e29bf8ec4adce63aa5925d549c105esewardj      }
22279334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
22289334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                               nameISize(szs), nameISize(szd),
22299334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj                               dis_buf, nameIReg(szd,gregOfRM(rm)));
22300611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      return len+delta;
22319334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   }
22329334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj}
22339334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
22349690d927540d730525a5f7f14663f3ceaa7818dasewardj
22359690d927540d730525a5f7f14663f3ceaa7818dasewardj/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
22369690d927540d730525a5f7f14663f3ceaa7818dasewardj   16 / 8 bit quantity in the given IRTemp.  */
22379690d927540d730525a5f7f14663f3ceaa7818dasewardjstatic
22389690d927540d730525a5f7f14663f3ceaa7818dasewardjvoid codegen_div ( Int sz, IRTemp t, Bool signed_divide )
22399690d927540d730525a5f7f14663f3ceaa7818dasewardj{
2240e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj   IROp   op    = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2241e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj   IRTemp src64 = newTemp(Ity_I64);
2242e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj   IRTemp dst64 = newTemp(Ity_I64);
22439690d927540d730525a5f7f14663f3ceaa7818dasewardj   switch (sz) {
2244e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj      case 4:
22459690d927540d730525a5f7f14663f3ceaa7818dasewardj         assign( src64, binop(Iop_32HLto64,
2246e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj                              getIReg(4,R_EDX), getIReg(4,R_EAX)) );
22479690d927540d730525a5f7f14663f3ceaa7818dasewardj         assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
22488c7f1abe9e022f6382634efea09c9cac89ec6336sewardj         putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
22499690d927540d730525a5f7f14663f3ceaa7818dasewardj         putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
22509690d927540d730525a5f7f14663f3ceaa7818dasewardj         break;
2251e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj      case 2: {
2252e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2253e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2254e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         assign( src64, unop(widen3264,
2255e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj                             binop(Iop_16HLto32,
2256e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj                                   getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2257e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2258e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2259e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2260e5427e8407f108e5a3dc778e0d208e32a1f02db6sewardj         break;
22619690d927540d730525a5f7f14663f3ceaa7818dasewardj      }
22624e82db7b7141106436f7f543c30050f80fcc9933sewardj      case 1: {
22634e82db7b7141106436f7f543c30050f80fcc9933sewardj         IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
22644e82db7b7141106436f7f543c30050f80fcc9933sewardj         IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
22654e82db7b7141106436f7f543c30050f80fcc9933sewardj         IROp widen816  = signed_divide ? Iop_8Sto16  : Iop_8Uto16;
22664e82db7b7141106436f7f543c30050f80fcc9933sewardj         assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
22674e82db7b7141106436f7f543c30050f80fcc9933sewardj         assign( dst64,
22684e82db7b7141106436f7f543c30050f80fcc9933sewardj                 binop(op, mkexpr(src64),
22694e82db7b7141106436f7f543c30050f80fcc9933sewardj                           unop(widen1632, unop(widen816, mkexpr(t)))) );
22704e82db7b7141106436f7f543c30050f80fcc9933sewardj         putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
22714e82db7b7141106436f7f543c30050f80fcc9933sewardj                           unop(Iop_64to32,mkexpr(dst64)))) );
22724e82db7b7141106436f7f543c30050f80fcc9933sewardj         putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
22734e82db7b7141106436f7f543c30050f80fcc9933sewardj                           unop(Iop_64HIto32,mkexpr(dst64)))) );
22744e82db7b7141106436f7f543c30050f80fcc9933sewardj         break;
22754e82db7b7141106436f7f543c30050f80fcc9933sewardj      }
22769690d927540d730525a5f7f14663f3ceaa7818dasewardj      default: vpanic("codegen_div(x86)");
22779690d927540d730525a5f7f14663f3ceaa7818dasewardj   }
22789690d927540d730525a5f7f14663f3ceaa7818dasewardj}
227941f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
228041f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
228141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardjstatic
2282e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardjUInt dis_Grp1 ( UChar sorb, Bool locked,
228352d049186d07991237a825ec88aa7f1f303edb70sewardj                Int delta, UChar modrm,
228441f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj                Int am_sz, Int d_sz, Int sz, UInt d32 )
228541f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj{
228641f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   Int     len;
2287c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar   dis_buf[50];
2288e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRType  ty   = szToITy(sz);
2289e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRTemp  dst1 = newTemp(ty);
2290e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRTemp  src  = newTemp(ty);
2291e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   IRTemp  dst0 = newTemp(ty);
229292d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp  addr = IRTemp_INVALID;
229366de22767fc526eff52133c18d4a42a9b25d5f18sewardj   IROp    op8  = Iop_INVALID;
2294180e8b39d5b4271e64634162986749c43536647csewardj   UInt    mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
229541f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
229641f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   switch (gregOfRM(modrm)) {
2297e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      case 0: op8 = Iop_Add8; break;  case 1: op8 = Iop_Or8;  break;
229866de22767fc526eff52133c18d4a42a9b25d5f18sewardj      case 2: break;  // ADC
229966de22767fc526eff52133c18d4a42a9b25d5f18sewardj      case 3: break;  // SBB
2300e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      case 4: op8 = Iop_And8; break;  case 5: op8 = Iop_Sub8; break;
2301e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      case 6: op8 = Iop_Xor8; break;  case 7: op8 = Iop_Sub8; break;
2302d51dc81599cba69ddc133f56c743205330f9dc40sewardj      /*NOTREACHED*/
230341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      default: vpanic("dis_Grp1: unhandled case");
230441f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   }
230541f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
230641f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   if (epartIsReg(modrm)) {
230741f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      vassert(am_sz == 1);
230841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
230941f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      assign(dst0, getIReg(sz,eregOfRM(modrm)));
2310180e8b39d5b4271e64634162986749c43536647csewardj      assign(src,  mkU(ty,d32 & mask));
231141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
2312180e8b39d5b4271e64634162986749c43536647csewardj      if (gregOfRM(modrm) == 2 /* ADC */) {
2313e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_ADC( sz, dst1, dst0, src,
2314e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2315180e8b39d5b4271e64634162986749c43536647csewardj      } else
2316180e8b39d5b4271e64634162986749c43536647csewardj      if (gregOfRM(modrm) == 3 /* SBB */) {
2317e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         helper_SBB( sz, dst1, dst0, src,
2318e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2319180e8b39d5b4271e64634162986749c43536647csewardj      } else {
2320180e8b39d5b4271e64634162986749c43536647csewardj         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
23215bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         if (isAddSub(op8))
23222a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2323b9c5cf639b3b21b972599d27207a033afc76ef67sewardj         else
23242a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1(op8, dst1, ty);
2325180e8b39d5b4271e64634162986749c43536647csewardj      }
232641f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
232741f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      if (gregOfRM(modrm) < 7)
2328e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj         putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
232941f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
233041f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      delta += (am_sz + d_sz);
233141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
233241f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj                              nameIReg(sz,eregOfRM(modrm)));
233341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   } else {
2334e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      addr = disAMode ( &len, sorb, delta, dis_buf);
233541f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
2336940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      assign(dst0, loadLE(ty,mkexpr(addr)));
2337180e8b39d5b4271e64634162986749c43536647csewardj      assign(src, mkU(ty,d32 & mask));
233841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
233966de22767fc526eff52133c18d4a42a9b25d5f18sewardj      if (gregOfRM(modrm) == 2 /* ADC */) {
2340e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (locked) {
2341e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* cas-style store */
2342e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_ADC( sz, dst1, dst0, src,
2343e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                       /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2344e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         } else {
2345e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* normal store */
2346e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_ADC( sz, dst1, dst0, src,
2347e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                        /*store*/addr, IRTemp_INVALID, 0 );
2348e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
23493af115ff8c215db41dff92da266a036c59eaec95sewardj      } else
235066de22767fc526eff52133c18d4a42a9b25d5f18sewardj      if (gregOfRM(modrm) == 3 /* SBB */) {
2351e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (locked) {
2352e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* cas-style store */
2353e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_SBB( sz, dst1, dst0, src,
2354e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                       /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2355e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         } else {
2356e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            /* normal store */
2357e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            helper_SBB( sz, dst1, dst0, src,
2358e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                        /*store*/addr, IRTemp_INVALID, 0 );
2359e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
23603af115ff8c215db41dff92da266a036c59eaec95sewardj      } else {
23613af115ff8c215db41dff92da266a036c59eaec95sewardj         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2362e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (gregOfRM(modrm) < 7) {
2363e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
2364e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr), mkexpr(dst0)/*expVal*/,
2365e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                    mkexpr(dst1)/*newVal*/,
2366e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                    guest_EIP_curr_instr );
2367e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
2368e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE(mkexpr(addr), mkexpr(dst1));
2369e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
2370e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
23715bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         if (isAddSub(op8))
23722a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2373b9c5cf639b3b21b972599d27207a033afc76ef67sewardj         else
23742a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1(op8, dst1, ty);
23753af115ff8c215db41dff92da266a036c59eaec95sewardj      }
237641f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
237741f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      delta += (len+d_sz);
237841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
237941f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj                              d32, dis_buf);
238041f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   }
238141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj   return delta;
238241f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj}
238341f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
238441f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj
23856d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj/* Group 2 extended opcodes.  shift_expr must be an 8-bit typed
23866d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   expression. */
23876d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj
2388e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardjstatic
238952d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_Grp2 ( UChar sorb,
239052d049186d07991237a825ec88aa7f1f303edb70sewardj                Int delta, UChar modrm,
23916d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj                Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
239255085f8680acc89d727e321f3b34cae1a8c4093aflorian                const HChar* shift_expr_txt, Bool* decode_OK )
2393e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj{
2394e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   /* delta on entry points at the modrm byte. */
2395c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar  dis_buf[50];
23966d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   Int    len;
23972eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj   Bool   isShift, isRotate, isRotateC;
23986d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRType ty    = szToITy(sz);
23996d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp dst0  = newTemp(ty);
24006d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp dst1  = newTemp(ty);
240192d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp addr  = IRTemp_INVALID;
2402e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2403d51dc81599cba69ddc133f56c743205330f9dc40sewardj   *decode_OK = True;
2404d51dc81599cba69ddc133f56c743205330f9dc40sewardj
2405e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   vassert(sz == 1 || sz == 2 || sz == 4);
2406e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2407e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   /* Put value to shift/rotate in dst0. */
2408e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   if (epartIsReg(modrm)) {
2409e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      assign(dst0, getIReg(sz, eregOfRM(modrm)));
2410940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      delta += (am_sz + d_sz);
2411e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   } else {
2412940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      addr = disAMode ( &len, sorb, delta, dis_buf);
2413940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      assign(dst0, loadLE(ty,mkexpr(addr)));
2414940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      delta += len + d_sz;
2415e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   }
2416e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2417e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   isShift = False;
2418d6b43fd4fcdb151c3fefb213de4dd64f8bb247b3tom   switch (gregOfRM(modrm)) { case 4: case 5: case 6: case 7: isShift = True; }
2419e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2420750f407b6be1aac303964a219acf0a6de8b8c4dasewardj   isRotate = False;
2421750f407b6be1aac303964a219acf0a6de8b8c4dasewardj   switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2422750f407b6be1aac303964a219acf0a6de8b8c4dasewardj
24232eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj   isRotateC = False;
24242eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj   switch (gregOfRM(modrm)) { case 2: case 3: isRotateC = True; }
24259aebb0c3f7a7f43313786826f31402f2b733badfsewardj
24262eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj   if (!isShift && !isRotate && !isRotateC) {
2427d51dc81599cba69ddc133f56c743205330f9dc40sewardj      /*NOTREACHED*/
24288c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      vpanic("dis_Grp2(Reg): unhandled case(x86)");
24298c7f1abe9e022f6382634efea09c9cac89ec6336sewardj   }
24308c7f1abe9e022f6382634efea09c9cac89ec6336sewardj
24312eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj   if (isRotateC) {
24322eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj      /* call a helper; these insns are so ridiculous they do not
24332eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj         deserve better */
24342eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj      Bool     left = toBool(gregOfRM(modrm) == 2);
24359aebb0c3f7a7f43313786826f31402f2b733badfsewardj      IRTemp   r64  = newTemp(Ity_I64);
2436f96552617c82834ece36184e674e249faa899b2fsewardj      IRExpr** args
2437f96552617c82834ece36184e674e249faa899b2fsewardj         = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2438f96552617c82834ece36184e674e249faa899b2fsewardj                          widenUto32(shift_expr),   /* rotate amount */
24392a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                          widenUto32(mk_x86g_calculate_eflags_all()),
2440f96552617c82834ece36184e674e249faa899b2fsewardj                          mkU32(sz) );
2441f96552617c82834ece36184e674e249faa899b2fsewardj      assign( r64, mkIRExprCCall(
24428ea867b06de73d909c29e243407713c291c8414esewardj                      Ity_I64,
2443f96552617c82834ece36184e674e249faa899b2fsewardj                      0/*regparm*/,
24442eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj                      left ? "x86g_calculate_RCL" : "x86g_calculate_RCR",
24452eef773d07df9bbc5d62c0058ae99d5511c2759dsewardj                      left ? &x86g_calculate_RCL  : &x86g_calculate_RCR,
24468ea867b06de73d909c29e243407713c291c8414esewardj                      args
2447f96552617c82834ece36184e674e249faa899b2fsewardj                   )
2448f96552617c82834ece36184e674e249faa899b2fsewardj            );
24499aebb0c3f7a7f43313786826f31402f2b733badfsewardj      /* new eflags in hi half r64; new value in lo half r64 */
24509aebb0c3f7a7f43313786826f31402f2b733badfsewardj      assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
24512a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
24522a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
24532a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2454a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      /* Set NDEP even though it isn't used.  This makes redundant-PUT
2455a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj         elimination of previous stores to this field work better. */
2456a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
24579aebb0c3f7a7f43313786826f31402f2b733badfsewardj   }
24589aebb0c3f7a7f43313786826f31402f2b733badfsewardj
2459e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   if (isShift) {
2460e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2461c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      IRTemp pre32     = newTemp(Ity_I32);
2462c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      IRTemp res32     = newTemp(Ity_I32);
2463c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      IRTemp res32ss   = newTemp(Ity_I32);
24646d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj      IRTemp shift_amt = newTemp(Ity_I8);
2465c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      IROp   op32;
2466e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2467e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      switch (gregOfRM(modrm)) {
2468c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         case 4: op32 = Iop_Shl32; break;
2469c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         case 5: op32 = Iop_Shr32; break;
2470d6b43fd4fcdb151c3fefb213de4dd64f8bb247b3tom         case 6: op32 = Iop_Shl32; break;
2471c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         case 7: op32 = Iop_Sar32; break;
2472d51dc81599cba69ddc133f56c743205330f9dc40sewardj         /*NOTREACHED*/
2473e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj         default: vpanic("dis_Grp2:shift"); break;
2474e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      }
2475e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2476c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* Widen the value to be shifted to 32 bits, do the shift, and
2477c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         narrow back down.  This seems surprisingly long-winded, but
2478c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         unfortunately the Intel semantics requires that 8/16-bit
2479c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         shifts give defined results for shift values all the way up
2480c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         to 31, and this seems the simplest way to do it.  It has the
2481c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         advantage that the only IR level shifts generated are of 32
2482c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         bit values, and the shift amount is guaranteed to be in the
2483c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         range 0 .. 31, thereby observing the IR semantics requiring
2484c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         all shift values to be in the range 0 .. 2^word_size-1. */
2485c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
2486c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* shift_amt = shift_expr & 31, regardless of operation size */
2487c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2488c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
2489c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* suitably widen the value to be shifted to 32 bits. */
2490c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2491c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj                                     : widenUto32(mkexpr(dst0)) );
2492c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
2493c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* res32 = pre32 `shift` shift_amt */
2494c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2495c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
2496c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2497c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      assign( res32ss,
2498c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj              binop(op32,
2499c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj                    mkexpr(pre32),
2500c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj                    binop(Iop_And8,
2501c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj                          binop(Iop_Sub8,
2502c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj                                mkexpr(shift_amt), mkU8(1)),
2503c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj                          mkU8(31))) );
2504e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2505e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      /* Build the flags thunk. */
25062a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
2507c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
2508c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* Narrow the result back down. */
2509c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      assign( dst1, narrowTo(ty, mkexpr(res32)) );
2510750f407b6be1aac303964a219acf0a6de8b8c4dasewardj
25111813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   } /* if (isShift) */
25121813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
25131813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   else
2514750f407b6be1aac303964a219acf0a6de8b8c4dasewardj   if (isRotate) {
25157ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      Int    ccOp      = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
25162d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool   left      = toBool(gregOfRM(modrm) == 0);
25177ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      IRTemp rot_amt   = newTemp(Ity_I8);
25187ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      IRTemp rot_amt32 = newTemp(Ity_I8);
25197ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      IRTemp oldFlags  = newTemp(Ity_I32);
2520750f407b6be1aac303964a219acf0a6de8b8c4dasewardj
2521750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      /* rot_amt = shift_expr & mask */
2522c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      /* By masking the rotate amount thusly, the IR-level Shl/Shr
2523c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         expressions never shift beyond the word size and thus remain
2524c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj         well defined. */
25257ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
25267ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj
25277ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      if (ty == Ity_I32)
25287ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj         assign(rot_amt, mkexpr(rot_amt32));
25297ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj      else
25307ebbdae2ab861210ec0fa997c9e9e810e81c869dsewardj         assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
2531750f407b6be1aac303964a219acf0a6de8b8c4dasewardj
2532750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      if (left) {
25331813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
2534750f407b6be1aac303964a219acf0a6de8b8c4dasewardj         /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2535750f407b6be1aac303964a219acf0a6de8b8c4dasewardj         assign(dst1,
2536750f407b6be1aac303964a219acf0a6de8b8c4dasewardj            binop( mkSizedOp(ty,Iop_Or8),
2537750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                   binop( mkSizedOp(ty,Iop_Shl8),
2538750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                          mkexpr(dst0),
2539750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                          mkexpr(rot_amt)
2540750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                   ),
2541750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                   binop( mkSizedOp(ty,Iop_Shr8),
2542750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                          mkexpr(dst0),
2543750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                          binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2544750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                   )
2545750f407b6be1aac303964a219acf0a6de8b8c4dasewardj            )
2546750f407b6be1aac303964a219acf0a6de8b8c4dasewardj         );
25472a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         ccOp += X86G_CC_OP_ROLB;
25481813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
25491813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      } else { /* right */
25501813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
25511813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
25521813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         assign(dst1,
25531813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            binop( mkSizedOp(ty,Iop_Or8),
25541813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                   binop( mkSizedOp(ty,Iop_Shr8),
25551813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                          mkexpr(dst0),
25561813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                          mkexpr(rot_amt)
25571813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                   ),
25581813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                   binop( mkSizedOp(ty,Iop_Shl8),
25591813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                          mkexpr(dst0),
25601813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                          binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2561750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                   )
2562750f407b6be1aac303964a219acf0a6de8b8c4dasewardj            )
2563750f407b6be1aac303964a219acf0a6de8b8c4dasewardj         );
25642a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         ccOp += X86G_CC_OP_RORB;
2565c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
2566750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      }
2567c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj
25681813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      /* dst1 now holds the rotated value.  Build flag thunk.  We
25691813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         need the resulting value for this, and the previous flags.
25701813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         Except don't set it if the rotate count is zero. */
25711813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
25722a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      assign(oldFlags, mk_x86g_calculate_eflags_all());
25731813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
2574009230b9758291b594e60d7c0243a73d53e81854sewardj      /* rot_amt32 :: Ity_I8.  We need to convert it to I1. */
2575009230b9758291b594e60d7c0243a73d53e81854sewardj      IRTemp rot_amt32b = newTemp(Ity_I1);
2576009230b9758291b594e60d7c0243a73d53e81854sewardj      assign(rot_amt32b, binop(Iop_CmpNE8, mkexpr(rot_amt32), mkU8(0)) );
2577009230b9758291b594e60d7c0243a73d53e81854sewardj
25782a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      /* CC_DEP1 is the rotated value.  CC_NDEP is flags before. */
25791813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      stmt( IRStmt_Put( OFFB_CC_OP,
258099dd03e04a6914d90d5fee727d61d76905334becflorian                        IRExpr_ITE( mkexpr(rot_amt32b),
258199dd03e04a6914d90d5fee727d61d76905334becflorian                                    mkU32(ccOp),
258299dd03e04a6914d90d5fee727d61d76905334becflorian                                    IRExpr_Get(OFFB_CC_OP,Ity_I32) ) ));
25832a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      stmt( IRStmt_Put( OFFB_CC_DEP1,
258499dd03e04a6914d90d5fee727d61d76905334becflorian                        IRExpr_ITE( mkexpr(rot_amt32b),
258599dd03e04a6914d90d5fee727d61d76905334becflorian                                    widenUto32(mkexpr(dst1)),
258699dd03e04a6914d90d5fee727d61d76905334becflorian                                    IRExpr_Get(OFFB_CC_DEP1,Ity_I32) ) ));
25872a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      stmt( IRStmt_Put( OFFB_CC_DEP2,
258899dd03e04a6914d90d5fee727d61d76905334becflorian                        IRExpr_ITE( mkexpr(rot_amt32b),
258999dd03e04a6914d90d5fee727d61d76905334becflorian                                    mkU32(0),
259099dd03e04a6914d90d5fee727d61d76905334becflorian                                    IRExpr_Get(OFFB_CC_DEP2,Ity_I32) ) ));
25912a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      stmt( IRStmt_Put( OFFB_CC_NDEP,
259299dd03e04a6914d90d5fee727d61d76905334becflorian                        IRExpr_ITE( mkexpr(rot_amt32b),
259399dd03e04a6914d90d5fee727d61d76905334becflorian                                    mkexpr(oldFlags),
259499dd03e04a6914d90d5fee727d61d76905334becflorian                                    IRExpr_Get(OFFB_CC_NDEP,Ity_I32) ) ));
25951813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   } /* if (isRotate) */
2596e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2597e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   /* Save result, and finish up. */
2598e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   if (epartIsReg(modrm)) {
2599e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2600f48ac19a67a98af44fe452c8c2be4192ac94b62dsewardj      if (vex_traceflags & VEX_TRACE_FE) {
2601e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj         vex_printf("%s%c ",
2602e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj                    nameGrp2(gregOfRM(modrm)), nameISize(sz) );
26036d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj         if (shift_expr_txt)
26046d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj            vex_printf("%s", shift_expr_txt);
26056d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj         else
26066d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj            ppIRExpr(shift_expr);
2607e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj         vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2608e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      }
2609e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   } else {
2610940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      storeLE(mkexpr(addr), mkexpr(dst1));
2611f48ac19a67a98af44fe452c8c2be4192ac94b62dsewardj      if (vex_traceflags & VEX_TRACE_FE) {
2612940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         vex_printf("%s%c ",
2613940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                    nameGrp2(gregOfRM(modrm)), nameISize(sz) );
26146d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj         if (shift_expr_txt)
26156d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj            vex_printf("%s", shift_expr_txt);
26166d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj         else
26176d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj            ppIRExpr(shift_expr);
2618940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         vex_printf(", %s\n", dis_buf);
2619e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      }
2620940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   }
2621e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   return delta;
2622e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj}
2623e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2624e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2625490ad3820487e34854c46befcc9c755d6afc2519sewardj/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2626490ad3820487e34854c46befcc9c755d6afc2519sewardjstatic
262752d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_Grp8_Imm ( UChar sorb,
2628e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                    Bool locked,
262952d049186d07991237a825ec88aa7f1f303edb70sewardj                    Int delta, UChar modrm,
2630490ad3820487e34854c46befcc9c755d6afc2519sewardj                    Int am_sz, Int sz, UInt src_val,
2631490ad3820487e34854c46befcc9c755d6afc2519sewardj                    Bool* decode_OK )
2632490ad3820487e34854c46befcc9c755d6afc2519sewardj{
2633490ad3820487e34854c46befcc9c755d6afc2519sewardj   /* src_val denotes a d8.
2634490ad3820487e34854c46befcc9c755d6afc2519sewardj      And delta on entry points at the modrm byte. */
2635490ad3820487e34854c46befcc9c755d6afc2519sewardj
2636490ad3820487e34854c46befcc9c755d6afc2519sewardj   IRType ty     = szToITy(sz);
2637490ad3820487e34854c46befcc9c755d6afc2519sewardj   IRTemp t2     = newTemp(Ity_I32);
2638490ad3820487e34854c46befcc9c755d6afc2519sewardj   IRTemp t2m    = newTemp(Ity_I32);
2639490ad3820487e34854c46befcc9c755d6afc2519sewardj   IRTemp t_addr = IRTemp_INVALID;
2640490ad3820487e34854c46befcc9c755d6afc2519sewardj   HChar  dis_buf[50];
2641490ad3820487e34854c46befcc9c755d6afc2519sewardj   UInt   mask;
2642e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
2643490ad3820487e34854c46befcc9c755d6afc2519sewardj   /* we're optimists :-) */
2644490ad3820487e34854c46befcc9c755d6afc2519sewardj   *decode_OK = True;
2645cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
2646490ad3820487e34854c46befcc9c755d6afc2519sewardj   /* Limit src_val -- the bit offset -- to something within a word.
2647490ad3820487e34854c46befcc9c755d6afc2519sewardj      The Intel docs say that literal offsets larger than a word are
2648490ad3820487e34854c46befcc9c755d6afc2519sewardj      masked in this way. */
2649490ad3820487e34854c46befcc9c755d6afc2519sewardj   switch (sz) {
2650490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 2:  src_val &= 15; break;
2651490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 4:  src_val &= 31; break;
2652490ad3820487e34854c46befcc9c755d6afc2519sewardj      default: *decode_OK = False; return delta;
2653490ad3820487e34854c46befcc9c755d6afc2519sewardj   }
2654490ad3820487e34854c46befcc9c755d6afc2519sewardj
2655490ad3820487e34854c46befcc9c755d6afc2519sewardj   /* Invent a mask suitable for the operation. */
2656490ad3820487e34854c46befcc9c755d6afc2519sewardj   switch (gregOfRM(modrm)) {
2657490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 4: /* BT */  mask = 0;               break;
2658490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 5: /* BTS */ mask = 1 << src_val;    break;
2659490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 6: /* BTR */ mask = ~(1 << src_val); break;
2660490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 7: /* BTC */ mask = 1 << src_val;    break;
2661490ad3820487e34854c46befcc9c755d6afc2519sewardj         /* If this needs to be extended, probably simplest to make a
2662490ad3820487e34854c46befcc9c755d6afc2519sewardj            new function to handle the other cases (0 .. 3).  The
2663490ad3820487e34854c46befcc9c755d6afc2519sewardj            Intel docs do however not indicate any use for 0 .. 3, so
2664490ad3820487e34854c46befcc9c755d6afc2519sewardj            we don't expect this to happen. */
2665490ad3820487e34854c46befcc9c755d6afc2519sewardj      default: *decode_OK = False; return delta;
2666490ad3820487e34854c46befcc9c755d6afc2519sewardj   }
2667490ad3820487e34854c46befcc9c755d6afc2519sewardj
2668490ad3820487e34854c46befcc9c755d6afc2519sewardj   /* Fetch the value to be tested and modified into t2, which is
2669490ad3820487e34854c46befcc9c755d6afc2519sewardj      32-bits wide regardless of sz. */
2670490ad3820487e34854c46befcc9c755d6afc2519sewardj   if (epartIsReg(modrm)) {
2671490ad3820487e34854c46befcc9c755d6afc2519sewardj      vassert(am_sz == 1);
26725a8334e7eb11f2d194f4c6ed9472027af21ab4ebsewardj      assign( t2, widenUto32(getIReg(sz, eregOfRM(modrm))) );
2673490ad3820487e34854c46befcc9c755d6afc2519sewardj      delta += (am_sz + 1);
2674490ad3820487e34854c46befcc9c755d6afc2519sewardj      DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2675490ad3820487e34854c46befcc9c755d6afc2519sewardj                              src_val, nameIReg(sz,eregOfRM(modrm)));
2676490ad3820487e34854c46befcc9c755d6afc2519sewardj   } else {
2677490ad3820487e34854c46befcc9c755d6afc2519sewardj      Int len;
2678490ad3820487e34854c46befcc9c755d6afc2519sewardj      t_addr = disAMode ( &len, sorb, delta, dis_buf);
2679490ad3820487e34854c46befcc9c755d6afc2519sewardj      delta  += (len+1);
2680490ad3820487e34854c46befcc9c755d6afc2519sewardj      assign( t2, widenUto32(loadLE(ty, mkexpr(t_addr))) );
2681490ad3820487e34854c46befcc9c755d6afc2519sewardj      DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2682490ad3820487e34854c46befcc9c755d6afc2519sewardj                              src_val, dis_buf);
2683490ad3820487e34854c46befcc9c755d6afc2519sewardj   }
2684490ad3820487e34854c46befcc9c755d6afc2519sewardj
2685490ad3820487e34854c46befcc9c755d6afc2519sewardj   /* Compute the new value into t2m, if non-BT. */
2686490ad3820487e34854c46befcc9c755d6afc2519sewardj   switch (gregOfRM(modrm)) {
2687490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 4: /* BT */
2688490ad3820487e34854c46befcc9c755d6afc2519sewardj         break;
2689490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 5: /* BTS */
2690490ad3820487e34854c46befcc9c755d6afc2519sewardj         assign( t2m, binop(Iop_Or32, mkU32(mask), mkexpr(t2)) );
2691490ad3820487e34854c46befcc9c755d6afc2519sewardj         break;
2692490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 6: /* BTR */
2693490ad3820487e34854c46befcc9c755d6afc2519sewardj         assign( t2m, binop(Iop_And32, mkU32(mask), mkexpr(t2)) );
2694490ad3820487e34854c46befcc9c755d6afc2519sewardj         break;
2695490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 7: /* BTC */
2696490ad3820487e34854c46befcc9c755d6afc2519sewardj         assign( t2m, binop(Iop_Xor32, mkU32(mask), mkexpr(t2)) );
2697490ad3820487e34854c46befcc9c755d6afc2519sewardj         break;
2698ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      default:
2699ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj         /*NOTREACHED*/ /*the previous switch guards this*/
2700490ad3820487e34854c46befcc9c755d6afc2519sewardj         vassert(0);
2701490ad3820487e34854c46befcc9c755d6afc2519sewardj   }
2702490ad3820487e34854c46befcc9c755d6afc2519sewardj
2703e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* Write the result back, if non-BT.  If the CAS fails then we
2704e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      side-exit from the trace at this point, and so the flag state is
2705e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      not affected.  This is of course as required. */
2706490ad3820487e34854c46befcc9c755d6afc2519sewardj   if (gregOfRM(modrm) != 4 /* BT */) {
2707490ad3820487e34854c46befcc9c755d6afc2519sewardj      if (epartIsReg(modrm)) {
2708e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         putIReg(sz, eregOfRM(modrm), narrowTo(ty, mkexpr(t2m)));
2709490ad3820487e34854c46befcc9c755d6afc2519sewardj      } else {
2710e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (locked) {
2711e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            casLE( mkexpr(t_addr),
2712e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                   narrowTo(ty, mkexpr(t2))/*expd*/,
2713e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                   narrowTo(ty, mkexpr(t2m))/*new*/,
2714e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                   guest_EIP_curr_instr );
2715e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         } else {
2716e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
2717e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         }
2718490ad3820487e34854c46befcc9c755d6afc2519sewardj      }
2719490ad3820487e34854c46befcc9c755d6afc2519sewardj   }
2720490ad3820487e34854c46befcc9c755d6afc2519sewardj
2721e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* Copy relevant bit from t2 into the carry flag. */
2722e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
2723e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
2724e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2725e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   stmt( IRStmt_Put(
2726e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            OFFB_CC_DEP1,
2727e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            binop(Iop_And32,
2728e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  binop(Iop_Shr32, mkexpr(t2), mkU8(src_val)),
2729e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  mkU32(1))
2730e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj       ));
2731e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
2732e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      elimination of previous stores to this field work better. */
2733e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
2734e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
2735490ad3820487e34854c46befcc9c755d6afc2519sewardj   return delta;
2736490ad3820487e34854c46befcc9c755d6afc2519sewardj}
2737cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
2738cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
27391813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj/* Signed/unsigned widening multiply.  Generate IR to multiply the
27401813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   value in EAX/AX/AL by the given IRTemp, and park the result in
27411813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   EDX:EAX/DX:AX/AX.
2742cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj*/
27431813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardjstatic void codegen_mulL_A_D ( Int sz, Bool syned,
274455085f8680acc89d727e321f3b34cae1a8c4093aflorian                               IRTemp tmp, const HChar* tmp_txt )
2745cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj{
2746cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   IRType ty = szToITy(sz);
2747cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   IRTemp t1 = newTemp(ty);
2748cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
27491813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   assign( t1, getIReg(sz, R_EAX) );
2750cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
2751cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   switch (ty) {
2752b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      case Ity_I32: {
2753b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         IRTemp res64   = newTemp(Ity_I64);
2754948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         IRTemp resHi   = newTemp(Ity_I32);
2755948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         IRTemp resLo   = newTemp(Ity_I32);
2756b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         IROp   mulOp   = syned ? Iop_MullS32 : Iop_MullU32;
27572a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         UInt   tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
27582a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
2759b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2760948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2761948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         assign( resLo, unop(Iop_64to32,mkexpr(res64)));
2762948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         putIReg(4, R_EDX, mkexpr(resHi));
2763948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         putIReg(4, R_EAX, mkexpr(resLo));
2764b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         break;
2765b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      }
2766b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      case Ity_I16: {
2767b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         IRTemp res32   = newTemp(Ity_I32);
2768948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         IRTemp resHi   = newTemp(Ity_I16);
2769948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         IRTemp resLo   = newTemp(Ity_I16);
2770b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         IROp   mulOp   = syned ? Iop_MullS16 : Iop_MullU16;
27712a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         UInt   tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
27722a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
2773b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2774948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2775948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         assign( resLo, unop(Iop_32to16,mkexpr(res32)));
2776948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         putIReg(2, R_EDX, mkexpr(resHi));
2777948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         putIReg(2, R_EAX, mkexpr(resLo));
2778b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         break;
2779b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      }
2780b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      case Ity_I8: {
2781b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         IRTemp res16   = newTemp(Ity_I16);
2782948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         IRTemp resHi   = newTemp(Ity_I8);
2783948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         IRTemp resLo   = newTemp(Ity_I8);
2784b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         IROp   mulOp   = syned ? Iop_MullS8 : Iop_MullU8;
27852a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         UInt   tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
27862a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
2787b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2788948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2789948d48be23eca9df7b9d33be5dca499affb7cb3asewardj         assign( resLo, unop(Iop_16to8,mkexpr(res16)));
2790b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         putIReg(2, R_EAX, mkexpr(res16));
2791b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         break;
2792b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      }
2793b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj      default:
2794b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj         vpanic("codegen_mulL_A_D(x86)");
2795cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   }
27961813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
2797cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj}
2798cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
2799940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
2800940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj/* Group 3 extended opcodes. */
2801940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardjstatic
2802e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardjUInt dis_Grp3 ( UChar sorb, Bool locked, Int sz, Int delta, Bool* decode_OK )
2803940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj{
2804c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   UInt    d32;
2805c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   UChar   modrm;
2806c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar   dis_buf[50];
2807c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   Int     len;
2808c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   IRTemp  addr;
2809940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   IRType  ty = szToITy(sz);
2810940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   IRTemp  t1 = newTemp(ty);
2811940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   IRTemp dst1, src, dst0;
2812d51dc81599cba69ddc133f56c743205330f9dc40sewardj
2813d51dc81599cba69ddc133f56c743205330f9dc40sewardj   *decode_OK = True; /* may change this later */
2814d51dc81599cba69ddc133f56c743205330f9dc40sewardj
2815940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   modrm = getIByte(delta);
2816e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
2817e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   if (locked && (gregOfRM(modrm) != 2 && gregOfRM(modrm) != 3)) {
2818e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* LOCK prefix only allowed with not and neg subopcodes */
2819e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      *decode_OK = False;
2820e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      return delta;
2821e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
2822e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
2823940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   if (epartIsReg(modrm)) {
2824940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      switch (gregOfRM(modrm)) {
2825c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         case 0: { /* TEST */
2826c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            delta++; d32 = getUDisp(sz, delta); delta += sz;
28275bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            dst1 = newTemp(ty);
28285bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            assign(dst1, binop(mkSizedOp(ty,Iop_And8),
28295bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                               getIReg(sz,eregOfRM(modrm)),
2830c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj                               mkU(ty,d32)));
28315bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            setFlags_DEP1( Iop_And8, dst1, ty );
2832c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2833c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj                                      nameIReg(sz, eregOfRM(modrm)));
2834c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            break;
2835c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         }
2836d51dc81599cba69ddc133f56c743205330f9dc40sewardj         case 1: /* UNDEFINED */
2837d51dc81599cba69ddc133f56c743205330f9dc40sewardj           /* The Intel docs imply this insn is undefined and binutils
2838d51dc81599cba69ddc133f56c743205330f9dc40sewardj              agrees.  Unfortunately Core 2 will run it (with who
2839d51dc81599cba69ddc133f56c743205330f9dc40sewardj              knows what result?)  sandpile.org reckons it's an alias
2840d51dc81599cba69ddc133f56c743205330f9dc40sewardj              for case 0.  We play safe. */
2841d51dc81599cba69ddc133f56c743205330f9dc40sewardj           *decode_OK = False;
2842d51dc81599cba69ddc133f56c743205330f9dc40sewardj           break;
2843940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         case 2: /* NOT */
2844940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            delta++;
2845940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            putIReg(sz, eregOfRM(modrm),
2846940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                        unop(mkSizedOp(ty,Iop_Not8),
2847940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj                             getIReg(sz, eregOfRM(modrm))));
2848940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2849940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            break;
2850940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         case 3: /* NEG */
2851940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            delta++;
2852940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            dst0 = newTemp(ty);
2853940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            src  = newTemp(ty);
2854940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            dst1 = newTemp(ty);
28555bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            assign(dst0, mkU(ty,0));
2856a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj            assign(src,  getIReg(sz,eregOfRM(modrm)));
2857eb17e49565dd7867a56c8ba6e45fdca01a576bb3sewardj            assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
28582a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
28595bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2860940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2861940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            break;
2862cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj         case 4: /* MUL (unsigned widening) */
2863cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj            delta++;
28641813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            src = newTemp(ty);
28655bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            assign(src, getIReg(sz,eregOfRM(modrm)));
28661813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
2867cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj            break;
2868caca9d0d3729c36af6ae02b0654cb289101248cbsewardj         case 5: /* IMUL (signed widening) */
2869caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            delta++;
28701813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            src = newTemp(ty);
28715bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            assign(src, getIReg(sz,eregOfRM(modrm)));
28721813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
2873caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            break;
287468511549b138ef55c8d31088cb0f20a72d83ab2bsewardj         case 6: /* DIV */
287568511549b138ef55c8d31088cb0f20a72d83ab2bsewardj            delta++;
287668511549b138ef55c8d31088cb0f20a72d83ab2bsewardj            assign( t1, getIReg(sz, eregOfRM(modrm)) );
287768511549b138ef55c8d31088cb0f20a72d83ab2bsewardj            codegen_div ( sz, t1, False );
287868511549b138ef55c8d31088cb0f20a72d83ab2bsewardj            DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
287968511549b138ef55c8d31088cb0f20a72d83ab2bsewardj            break;
2880caca9d0d3729c36af6ae02b0654cb289101248cbsewardj         case 7: /* IDIV */
2881caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            delta++;
2882caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            assign( t1, getIReg(sz, eregOfRM(modrm)) );
2883caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            codegen_div ( sz, t1, True );
2884caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2885caca9d0d3729c36af6ae02b0654cb289101248cbsewardj            break;
2886940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         default:
2887d51dc81599cba69ddc133f56c743205330f9dc40sewardj            /* This can't happen - gregOfRM should return 0 .. 7 only */
2888940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj            vpanic("Grp3(x86)");
2889940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      }
2890940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   } else {
2891c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      addr = disAMode ( &len, sorb, delta, dis_buf );
2892c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      t1   = newTemp(ty);
2893c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      delta += len;
2894c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      assign(t1, loadLE(ty,mkexpr(addr)));
2895c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      switch (gregOfRM(modrm)) {
2896c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         case 0: { /* TEST */
2897c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            d32 = getUDisp(sz, delta); delta += sz;
28985bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            dst1 = newTemp(ty);
28995bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            assign(dst1, binop(mkSizedOp(ty,Iop_And8),
29005bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                               mkexpr(t1), mkU(ty,d32)));
29015bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            setFlags_DEP1( Iop_And8, dst1, ty );
2902c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2903c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            break;
2904c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         }
2905d51dc81599cba69ddc133f56c743205330f9dc40sewardj         case 1: /* UNDEFINED */
2906d51dc81599cba69ddc133f56c743205330f9dc40sewardj           /* See comment above on R case */
2907d51dc81599cba69ddc133f56c743205330f9dc40sewardj           *decode_OK = False;
2908d51dc81599cba69ddc133f56c743205330f9dc40sewardj           break;
290978fe7910833f29826df06f3ff6f0238f0c41e6e2sewardj         case 2: /* NOT */
2910e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            dst1 = newTemp(ty);
2911e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            assign(dst1, unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2912e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
2913e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2914e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                    guest_EIP_curr_instr );
2915e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
2916e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE( mkexpr(addr), mkexpr(dst1) );
2917e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
291878fe7910833f29826df06f3ff6f0238f0c41e6e2sewardj            DIP("not%c %s\n", nameISize(sz), dis_buf);
291978fe7910833f29826df06f3ff6f0238f0c41e6e2sewardj            break;
29200c12ea83187de020a5484b4327e2427ea3451380sewardj         case 3: /* NEG */
29210c12ea83187de020a5484b4327e2427ea3451380sewardj            dst0 = newTemp(ty);
29220c12ea83187de020a5484b4327e2427ea3451380sewardj            src  = newTemp(ty);
29230c12ea83187de020a5484b4327e2427ea3451380sewardj            dst1 = newTemp(ty);
29245bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            assign(dst0, mkU(ty,0));
2925a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj            assign(src,  mkexpr(t1));
2926e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            assign(dst1, binop(mkSizedOp(ty,Iop_Sub8),
2927e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                               mkexpr(dst0), mkexpr(src)));
2928e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
2929e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2930e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                    guest_EIP_curr_instr );
2931e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
2932e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE( mkexpr(addr), mkexpr(dst1) );
2933e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
29342a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
29350c12ea83187de020a5484b4327e2427ea3451380sewardj            DIP("neg%c %s\n", nameISize(sz), dis_buf);
29360c12ea83187de020a5484b4327e2427ea3451380sewardj            break;
29371813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         case 4: /* MUL */
29381813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            codegen_mulL_A_D ( sz, False, t1, dis_buf );
29391813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            break;
29401813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         case 5: /* IMUL */
29411813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            codegen_mulL_A_D ( sz, True, t1, dis_buf );
29421813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            break;
29439690d927540d730525a5f7f14663f3ceaa7818dasewardj         case 6: /* DIV */
29449690d927540d730525a5f7f14663f3ceaa7818dasewardj            codegen_div ( sz, t1, False );
29459690d927540d730525a5f7f14663f3ceaa7818dasewardj            DIP("div%c %s\n", nameISize(sz), dis_buf);
29469690d927540d730525a5f7f14663f3ceaa7818dasewardj            break;
29471813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj         case 7: /* IDIV */
29481813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            codegen_div ( sz, t1, True );
29491813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            DIP("idiv%c %s\n", nameISize(sz), dis_buf);
29501813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj            break;
2951c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         default:
2952d51dc81599cba69ddc133f56c743205330f9dc40sewardj            /* This can't happen - gregOfRM should return 0 .. 7 only */
2953c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            vpanic("Grp3(x86)");
2954c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      }
2955940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   }
2956940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   return delta;
2957940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj}
2958940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
2959940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
2960c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj/* Group 4 extended opcodes. */
2961c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardjstatic
2962e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardjUInt dis_Grp4 ( UChar sorb, Bool locked, Int delta, Bool* decode_OK )
2963c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj{
2964c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   Int   alen;
2965c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   UChar modrm;
2966c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
2967c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   IRType ty = Ity_I8;
29687ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj   IRTemp t1 = newTemp(ty);
29697ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj   IRTemp t2 = newTemp(ty);
2970c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
2971d51dc81599cba69ddc133f56c743205330f9dc40sewardj   *decode_OK = True;
2972d51dc81599cba69ddc133f56c743205330f9dc40sewardj
2973c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   modrm = getIByte(delta);
2974e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
2975e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
2976e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* LOCK prefix only allowed with inc and dec subopcodes */
2977e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      *decode_OK = False;
2978e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      return delta;
2979e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
2980e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
2981c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   if (epartIsReg(modrm)) {
2982c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      assign(t1, getIReg(1, eregOfRM(modrm)));
2983c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      switch (gregOfRM(modrm)) {
29847ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj         case 0: /* INC */
29857ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
29867ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            putIReg(1, eregOfRM(modrm), mkexpr(t2));
29877ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            setFlags_INC_DEC( True, t2, ty );
29887ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            break;
2989c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         case 1: /* DEC */
2990c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2991c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            putIReg(1, eregOfRM(modrm), mkexpr(t2));
2992c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            setFlags_INC_DEC( False, t2, ty );
2993c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            break;
2994c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         default:
2995d51dc81599cba69ddc133f56c743205330f9dc40sewardj            *decode_OK = False;
2996d51dc81599cba69ddc133f56c743205330f9dc40sewardj            return delta;
2997c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      }
2998c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      delta++;
2999c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
3000c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj                      nameIReg(1, eregOfRM(modrm)));
3001c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   } else {
30027ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
30037ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      assign( t1, loadLE(ty, mkexpr(addr)) );
30047ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      switch (gregOfRM(modrm)) {
3005588ea765122c1ecb97991eea513b12504e35d55esewardj         case 0: /* INC */
3006588ea765122c1ecb97991eea513b12504e35d55esewardj            assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3007e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
3008e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3009e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                      guest_EIP_curr_instr );
3010e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
3011e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE( mkexpr(addr), mkexpr(t2) );
3012e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
3013588ea765122c1ecb97991eea513b12504e35d55esewardj            setFlags_INC_DEC( True, t2, ty );
3014588ea765122c1ecb97991eea513b12504e35d55esewardj            break;
30157ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj         case 1: /* DEC */
30167ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3017e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
3018e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3019e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                      guest_EIP_curr_instr );
3020e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
3021e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE( mkexpr(addr), mkexpr(t2) );
3022e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
30237ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            setFlags_INC_DEC( False, t2, ty );
30247ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj            break;
30257ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj         default:
3026d51dc81599cba69ddc133f56c743205330f9dc40sewardj            *decode_OK = False;
3027d51dc81599cba69ddc133f56c743205330f9dc40sewardj            return delta;
30287ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      }
30297ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      delta += alen;
30307ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
3031c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   }
3032c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   return delta;
3033c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj}
30340611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
30350611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
30360611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj/* Group 5 extended opcodes. */
30370611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardjstatic
3038e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardjUInt dis_Grp5 ( UChar sorb, Bool locked, Int sz, Int delta,
3039c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                /*MOD*/DisResult* dres, /*OUT*/Bool* decode_OK )
30400611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj{
30410611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   Int     len;
30420611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   UChar   modrm;
3043c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar   dis_buf[50];
304492d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp  addr = IRTemp_INVALID;
30450611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   IRType  ty = szToITy(sz);
30460611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   IRTemp  t1 = newTemp(ty);
304792d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp  t2 = IRTemp_INVALID;
30480611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
3049d51dc81599cba69ddc133f56c743205330f9dc40sewardj   *decode_OK = True;
3050d51dc81599cba69ddc133f56c743205330f9dc40sewardj
30510611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   modrm = getIByte(delta);
3052e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
3053e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
3054e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* LOCK prefix only allowed with inc and dec subopcodes */
3055e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      *decode_OK = False;
3056e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      return delta;
3057e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
3058e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
30590611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   if (epartIsReg(modrm)) {
3060940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      assign(t1, getIReg(sz,eregOfRM(modrm)));
30610611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      switch (gregOfRM(modrm)) {
306259ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj         case 0: /* INC */
306359ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            vassert(sz == 2 || sz == 4);
306459ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            t2 = newTemp(ty);
306559ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            assign(t2, binop(mkSizedOp(ty,Iop_Add8),
306659ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj                             mkexpr(t1), mkU(ty,1)));
306759ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            setFlags_INC_DEC( True, t2, ty );
306859ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            putIReg(sz,eregOfRM(modrm),mkexpr(t2));
306959ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            break;
307059ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj         case 1: /* DEC */
307159ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            vassert(sz == 2 || sz == 4);
307259ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            t2 = newTemp(ty);
307359ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
307459ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj                             mkexpr(t1), mkU(ty,1)));
307559ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            setFlags_INC_DEC( False, t2, ty );
307659ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            putIReg(sz,eregOfRM(modrm),mkexpr(t2));
307759ff5d42fdb118c084fa44cfb2d8ff81ff4a3a5fsewardj            break;
3078c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         case 2: /* call Ev */
3079c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            vassert(sz == 4);
3080c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            t2 = newTemp(Ity_I32);
3081c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3082c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            putIReg(4, R_ESP, mkexpr(t2));
30839e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+1));
3084c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_treg(dres, Ijk_Call, t1);
3085c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres->whatNext == Dis_StopHere);
3086c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            break;
30870611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         case 4: /* jmp Ev */
30880611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj            vassert(sz == 4);
3089c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_treg(dres, Ijk_Boring, t1);
3090c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres->whatNext == Dis_StopHere);
30910611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj            break;
309228905821e7c91626aa61ef496b597029b0b25e0dsewardj         case 6: /* PUSH Ev */
309328905821e7c91626aa61ef496b597029b0b25e0dsewardj            vassert(sz == 4 || sz == 2);
309428905821e7c91626aa61ef496b597029b0b25e0dsewardj            t2 = newTemp(Ity_I32);
309528905821e7c91626aa61ef496b597029b0b25e0dsewardj            assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
309628905821e7c91626aa61ef496b597029b0b25e0dsewardj            putIReg(4, R_ESP, mkexpr(t2) );
309728905821e7c91626aa61ef496b597029b0b25e0dsewardj            storeLE( mkexpr(t2), mkexpr(t1) );
309828905821e7c91626aa61ef496b597029b0b25e0dsewardj            break;
30990611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         default:
3100d51dc81599cba69ddc133f56c743205330f9dc40sewardj            *decode_OK = False;
3101d51dc81599cba69ddc133f56c743205330f9dc40sewardj            return delta;
31020611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      }
31030611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      delta++;
31040611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
31050611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                       nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
31060611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   } else {
31070611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      addr = disAMode ( &len, sorb, delta, dis_buf );
3108940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      assign(t1, loadLE(ty,mkexpr(addr)));
31090611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      switch (gregOfRM(modrm)) {
31100611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         case 0: /* INC */
31110611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj            t2 = newTemp(ty);
31120611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj            assign(t2, binop(mkSizedOp(ty,Iop_Add8),
31130611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                             mkexpr(t1), mkU(ty,1)));
3114e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
3115e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr),
3116e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                      mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3117e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
3118e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE(mkexpr(addr),mkexpr(t2));
3119e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
31200611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj            setFlags_INC_DEC( True, t2, ty );
31210611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj            break;
3122c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         case 1: /* DEC */
3123c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            t2 = newTemp(ty);
3124c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3125c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj                             mkexpr(t1), mkU(ty,1)));
3126e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            if (locked) {
3127e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               casLE( mkexpr(addr),
3128e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                      mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3129e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            } else {
3130e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               storeLE(mkexpr(addr),mkexpr(t2));
3131e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            }
3132c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            setFlags_INC_DEC( False, t2, ty );
3133c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj            break;
313477b86be374085943e902075b305ff047a053aac6sewardj         case 2: /* call Ev */
313577b86be374085943e902075b305ff047a053aac6sewardj            vassert(sz == 4);
313677b86be374085943e902075b305ff047a053aac6sewardj            t2 = newTemp(Ity_I32);
313777b86be374085943e902075b305ff047a053aac6sewardj            assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
313877b86be374085943e902075b305ff047a053aac6sewardj            putIReg(4, R_ESP, mkexpr(t2));
31399e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+len));
3140c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_treg(dres, Ijk_Call, t1);
3141c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres->whatNext == Dis_StopHere);
314277b86be374085943e902075b305ff047a053aac6sewardj            break;
314377b86be374085943e902075b305ff047a053aac6sewardj         case 4: /* JMP Ev */
314477b86be374085943e902075b305ff047a053aac6sewardj            vassert(sz == 4);
3145c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_treg(dres, Ijk_Boring, t1);
3146c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres->whatNext == Dis_StopHere);
314777b86be374085943e902075b305ff047a053aac6sewardj            break;
31480c12ea83187de020a5484b4327e2427ea3451380sewardj         case 6: /* PUSH Ev */
31490c12ea83187de020a5484b4327e2427ea3451380sewardj            vassert(sz == 4 || sz == 2);
31500c12ea83187de020a5484b4327e2427ea3451380sewardj            t2 = newTemp(Ity_I32);
31510c12ea83187de020a5484b4327e2427ea3451380sewardj            assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
31520c12ea83187de020a5484b4327e2427ea3451380sewardj            putIReg(4, R_ESP, mkexpr(t2) );
31535bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            storeLE( mkexpr(t2), mkexpr(t1) );
31540c12ea83187de020a5484b4327e2427ea3451380sewardj            break;
31550611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         default:
3156d51dc81599cba69ddc133f56c743205330f9dc40sewardj            *decode_OK = False;
3157d51dc81599cba69ddc133f56c743205330f9dc40sewardj            return delta;
31580611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      }
31590611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      delta += len;
31600611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
31610611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                       nameISize(sz), dis_buf);
31620611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   }
31630611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   return delta;
31640611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj}
31650611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
3166464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
316764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/*------------------------------------------------------------*/
316864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/*--- Disassembling string ops (including REP prefixes)    ---*/
316964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/*------------------------------------------------------------*/
317064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
317164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/* Code shared by all the string ops */
317264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
317364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjvoid dis_string_op_increment(Int sz, Int t_inc)
317464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
317564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   if (sz == 4 || sz == 2) {
317664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      assign( t_inc,
317764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj              binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
31786d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj                               mkU8(sz/2) ) );
317964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   } else {
318064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      assign( t_inc,
318164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj              IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
318264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   }
318364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
318464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
318564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
318664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjvoid dis_string_op( void (*dis_OP)( Int, IRTemp ),
318755085f8680acc89d727e321f3b34cae1a8c4093aflorian                    Int sz, const HChar* name, UChar sorb )
318864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
318964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp t_inc = newTemp(Ity_I32);
31909c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj   vassert(sorb == 0); /* hmm.  so what was the point of passing it in? */
319164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   dis_string_op_increment(sz, t_inc);
319264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   dis_OP( sz, t_inc );
319364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   DIP("%s%c\n", name, nameISize(sz));
319464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
319564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
319664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
319764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjvoid dis_MOVS ( Int sz, IRTemp t_inc )
319864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
319964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRType ty = szToITy(sz);
320064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp td = newTemp(Ity_I32);   /* EDI */
320164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp ts = newTemp(Ity_I32);   /* ESI */
320264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
320364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( td, getIReg(4, R_EDI) );
320464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( ts, getIReg(4, R_ESI) );
320564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
320664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
320764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
320864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
320964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
321064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
321164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
321210ca4eb0751a48347cb6f539aff8b015a4eb94fasewardjstatic
321310ca4eb0751a48347cb6f539aff8b015a4eb94fasewardjvoid dis_LODS ( Int sz, IRTemp t_inc )
321410ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj{
321510ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   IRType ty = szToITy(sz);
321610ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   IRTemp ts = newTemp(Ity_I32);   /* ESI */
321710ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj
321810ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   assign( ts, getIReg(4, R_ESI) );
321910ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj
322010ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   putIReg( sz, R_EAX, loadLE(ty, mkexpr(ts)) );
322110ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj
322210ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
322310ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj}
322464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
322564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
322664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjvoid dis_STOS ( Int sz, IRTemp t_inc )
322764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
322864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRType ty = szToITy(sz);
322964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp ta = newTemp(ty);        /* EAX */
323064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp td = newTemp(Ity_I32);   /* EDI */
323164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
323264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( ta, getIReg(sz, R_EAX) );
323364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( td, getIReg(4, R_EDI) );
323464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
32356d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   storeLE( mkexpr(td), mkexpr(ta) );
323664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
323764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
323864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
323964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
324064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
324164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjvoid dis_CMPS ( Int sz, IRTemp t_inc )
324264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
324364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRType ty  = szToITy(sz);
32446d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp tdv = newTemp(ty);      /* (EDI) */
32456d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp tsv = newTemp(ty);      /* (ESI) */
324664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp td  = newTemp(Ity_I32); /*  EDI  */
324764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp ts  = newTemp(Ity_I32); /*  ESI  */
324864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
324964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( td, getIReg(4, R_EDI) );
325064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( ts, getIReg(4, R_ESI) );
325164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
325264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( tdv, loadLE(ty,mkexpr(td)) );
3253b9c5cf639b3b21b972599d27207a033afc76ef67sewardj   assign( tsv, loadLE(ty,mkexpr(ts)) );
325464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
32552a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
325664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
325764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
325864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
325964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
326064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
326164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
326264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjvoid dis_SCAS ( Int sz, IRTemp t_inc )
326364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
326464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRType ty  = szToITy(sz);
32658229288c4fb1331c1e638bacdd55566e1caad9edsewardj   IRTemp ta  = newTemp(ty);       /*  EAX  */
326664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp td  = newTemp(Ity_I32);  /*  EDI  */
326764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp tdv = newTemp(ty);       /* (EDI) */
326864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
3269b9c5cf639b3b21b972599d27207a033afc76ef67sewardj   assign( ta, getIReg(sz, R_EAX) );
327064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( td, getIReg(4, R_EDI) );
327164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
327264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( tdv, loadLE(ty,mkexpr(td)) );
32732a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
327464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
327564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
327664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
32778229288c4fb1331c1e638bacdd55566e1caad9edsewardj
327864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
327964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/* Wrap the appropriate string op inside a REP/REPE/REPNE.
328064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   We assume the insn is the last one in the basic block, and so emit a jump
328164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   to the next insn, rather than just falling through. */
328264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
3283c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardjvoid dis_REP_op ( /*MOD*/DisResult* dres,
3284c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                  X86Condcode cond,
328564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj                  void (*dis_OP)(Int, IRTemp),
328655085f8680acc89d727e321f3b34cae1a8c4093aflorian                  Int sz, Addr32 eip, Addr32 eip_next, const HChar* name )
328764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
328864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp t_inc = newTemp(Ity_I32);
328964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp tc    = newTemp(Ity_I32);  /*  ECX  */
329064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
329164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( tc, getIReg(4,R_ECX) );
329264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
329364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
3294893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                      Ijk_Boring,
3295c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                      IRConst_U32(eip_next), OFFB_EIP ) );
329664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
329764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
329864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
329964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   dis_string_op_increment(sz, t_inc);
330064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   dis_OP (sz, t_inc);
330164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
33022a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   if (cond == X86CondAlways) {
3303c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      jmp_lit(dres, Ijk_Boring, eip);
3304c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      vassert(dres->whatNext == Dis_StopHere);
330564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   } else {
33062a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
3307893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                         Ijk_Boring,
3308c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                         IRConst_U32(eip), OFFB_EIP ) );
3309c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      jmp_lit(dres, Ijk_Boring, eip_next);
3310c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      vassert(dres->whatNext == Dis_StopHere);
331164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   }
331264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   DIP("%s%c\n", name, nameISize(sz));
331364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
331464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
3315464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
331664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/*------------------------------------------------------------*/
331764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/*--- Arithmetic, etc.                                     ---*/
331864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj/*------------------------------------------------------------*/
331964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
33202a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj/* IMUL E, G.  Supplied eip points to the modR/M byte. */
3321cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardjstatic
3322cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardjUInt dis_mul_E_G ( UChar       sorb,
3323cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj                   Int         size,
332452d049186d07991237a825ec88aa7f1f303edb70sewardj                   Int         delta0 )
3325cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj{
332671a653693124415c046b51438f748d8f7cada2f2sewardj   Int    alen;
3327c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar  dis_buf[50];
3328cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   UChar  rm = getIByte(delta0);
3329cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   IRType ty = szToITy(size);
33306d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp te = newTemp(ty);
33316d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp tg = newTemp(ty);
3332948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   IRTemp resLo = newTemp(ty);
333371a653693124415c046b51438f748d8f7cada2f2sewardj
3334948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   assign( tg, getIReg(size, gregOfRM(rm)) );
3335cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   if (epartIsReg(rm)) {
3336cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj      assign( te, getIReg(size, eregOfRM(rm)) );
3337948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   } else {
3338948d48be23eca9df7b9d33be5dca499affb7cb3asewardj      IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3339948d48be23eca9df7b9d33be5dca499affb7cb3asewardj      assign( te, loadLE(ty,mkexpr(addr)) );
3340948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   }
3341948d48be23eca9df7b9d33be5dca499affb7cb3asewardj
33422a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
3343948d48be23eca9df7b9d33be5dca499affb7cb3asewardj
33442a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
3345cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
3346948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3347948d48be23eca9df7b9d33be5dca499affb7cb3asewardj
3348948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   if (epartIsReg(rm)) {
33492a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      DIP("imul%c %s, %s\n", nameISize(size),
33502a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                             nameIReg(size,eregOfRM(rm)),
33512a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                             nameIReg(size,gregOfRM(rm)));
3352cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj      return 1+delta0;
3353cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   } else {
33542a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      DIP("imul%c %s, %s\n", nameISize(size),
33552a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                             dis_buf, nameIReg(size,gregOfRM(rm)));
335671a653693124415c046b51438f748d8f7cada2f2sewardj      return alen+delta0;
3357cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj   }
3358cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj}
3359cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
3360cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
33611813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj/* IMUL I * E -> G.  Supplied eip points to the modR/M byte. */
33621813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardjstatic
33631813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardjUInt dis_imul_I_E_G ( UChar       sorb,
33641813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                      Int         size,
336552d049186d07991237a825ec88aa7f1f303edb70sewardj                      Int         delta,
33661813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj                      Int         litsize )
33671813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj{
3368883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   Int    d32, alen;
3369c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar  dis_buf[50];
3370b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj   UChar  rm = getIByte(delta);
33711813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   IRType ty = szToITy(size);
33721813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   IRTemp te = newTemp(ty);
33731813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   IRTemp tl = newTemp(ty);
3374948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   IRTemp resLo = newTemp(ty);
33751813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
3376b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj   vassert(size == 1 || size == 2 || size == 4);
3377b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj
33781813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   if (epartIsReg(rm)) {
33791813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      assign(te, getIReg(size, eregOfRM(rm)));
33801813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      delta++;
33811813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   } else {
3382883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3383883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      assign(te, loadLE(ty, mkexpr(addr)));
3384883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      delta += alen;
33851813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   }
33861813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   d32 = getSDisp(litsize,delta);
33871813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   delta += litsize;
33881813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
3389b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj   if (size == 1) d32 &= 0xFF;
3390b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj   if (size == 2) d32 &= 0xFFFF;
3391b81f8b3e9110a5608094b8ec1a5c6d3c30a8e5aesewardj
33921813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   assign(tl, mkU(ty,d32));
3393948d48be23eca9df7b9d33be5dca499affb7cb3asewardj
33942a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
3395948d48be23eca9df7b9d33be5dca499affb7cb3asewardj
33962a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
3397948d48be23eca9df7b9d33be5dca499affb7cb3asewardj
3398948d48be23eca9df7b9d33be5dca499affb7cb3asewardj   putIReg(size, gregOfRM(rm), mkexpr(resLo));
33991813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
34001813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   DIP("imul %d, %s, %s\n", d32,
34011813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj       ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
34021813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj       nameIReg(size,gregOfRM(rm)) );
34031813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   return delta;
3404948d48be23eca9df7b9d33be5dca499affb7cb3asewardj}
34051813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
34061813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
34079a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj/* Generate an IR sequence to do a count-leading-zeroes operation on
34089a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   the supplied IRTemp, and return a new IRTemp holding the result.
34099a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   'ty' may be Ity_I16 or Ity_I32 only.  In the case where the
34109a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   argument is zero, return the number of bits in the word (the
34119a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   natural semantics). */
34129a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardjstatic IRTemp gen_LZCNT ( IRType ty, IRTemp src )
34139a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj{
34149a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   vassert(ty == Ity_I32 || ty == Ity_I16);
34159a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
34169a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   IRTemp src32 = newTemp(Ity_I32);
34179a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   assign(src32, widenUto32( mkexpr(src) ));
34189a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
34199a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   IRTemp src32x = newTemp(Ity_I32);
34209a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   assign(src32x,
34219a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj          binop(Iop_Shl32, mkexpr(src32),
34229a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                           mkU8(32 - 8 * sizeofIRType(ty))));
34239a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
34249a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   // Clz32 has undefined semantics when its input is zero, so
34259a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   // special-case around that.
34269a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   IRTemp res32 = newTemp(Ity_I32);
34279a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   assign(res32,
342899dd03e04a6914d90d5fee727d61d76905334becflorian          IRExpr_ITE(
3429009230b9758291b594e60d7c0243a73d53e81854sewardj             binop(Iop_CmpEQ32, mkexpr(src32x), mkU32(0)),
343099dd03e04a6914d90d5fee727d61d76905334becflorian             mkU32(8 * sizeofIRType(ty)),
343199dd03e04a6914d90d5fee727d61d76905334becflorian             unop(Iop_Clz32, mkexpr(src32x))
34329a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   ));
34339a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
34349a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   IRTemp res = newTemp(ty);
34359a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   assign(res, narrowTo(ty, mkexpr(res32)));
34369a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   return res;
34379a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj}
34389a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
34399a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
3440d1725d18b61bf7912a9099686179faef5815dba1sewardj/*------------------------------------------------------------*/
3441464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*---                                                      ---*/
3442464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*--- x87 FLOATING POINT INSTRUCTIONS                      ---*/
3443464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*---                                                      ---*/
3444d1725d18b61bf7912a9099686179faef5815dba1sewardj/*------------------------------------------------------------*/
3445d1725d18b61bf7912a9099686179faef5815dba1sewardj
3446207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* --- Helper functions for dealing with the register stack. --- */
3447207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3448893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj/* --- Set the emulation-warning pseudo-register. --- */
3449893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj
3450893aadad7f29f7801ce26cb7575c16e90bd3767fsewardjstatic void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3451893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj{
3452dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
34536ef84bed9bb3af22060eb1759788034602bbcc88florian   stmt( IRStmt_Put( OFFB_EMNOTE, e ) );
3454893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj}
3455893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj
345617442fe8094d0f82266e5a05509f62cac8f7539esewardj/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
3457207557ab2ea38239b670785c976b89d50bbb0eccsewardj
345817442fe8094d0f82266e5a05509f62cac8f7539esewardjstatic IRExpr* mkQNaN64 ( void )
3459207557ab2ea38239b670785c976b89d50bbb0eccsewardj{
346017442fe8094d0f82266e5a05509f62cac8f7539esewardj  /* QNaN is 0 2047 1 0(51times)
346117442fe8094d0f82266e5a05509f62cac8f7539esewardj     == 0b 11111111111b 1 0(51times)
346217442fe8094d0f82266e5a05509f62cac8f7539esewardj     == 0x7FF8 0000 0000 0000
346317442fe8094d0f82266e5a05509f62cac8f7539esewardj   */
346417442fe8094d0f82266e5a05509f62cac8f7539esewardj   return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
3465207557ab2ea38239b670785c976b89d50bbb0eccsewardj}
3466207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3467893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj/* --------- Get/put the top-of-stack pointer. --------- */
3468d1725d18b61bf7912a9099686179faef5815dba1sewardj
3469d1725d18b61bf7912a9099686179faef5815dba1sewardjstatic IRExpr* get_ftop ( void )
3470d1725d18b61bf7912a9099686179faef5815dba1sewardj{
3471d1725d18b61bf7912a9099686179faef5815dba1sewardj   return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3472d1725d18b61bf7912a9099686179faef5815dba1sewardj}
3473d1725d18b61bf7912a9099686179faef5815dba1sewardj
3474207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic void put_ftop ( IRExpr* e )
3475207557ab2ea38239b670785c976b89d50bbb0eccsewardj{
3476dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
3477207557ab2ea38239b670785c976b89d50bbb0eccsewardj   stmt( IRStmt_Put( OFFB_FTOP, e ) );
3478207557ab2ea38239b670785c976b89d50bbb0eccsewardj}
3479207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3480893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj/* --------- Get/put the C3210 bits. --------- */
3481bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
3482c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardjstatic IRExpr* get_C3210 ( void )
3483bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj{
3484c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj   return IRExpr_Get( OFFB_FC3210, Ity_I32 );
3485bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj}
3486bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
3487c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardjstatic void put_C3210 ( IRExpr* e )
3488bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj{
3489c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj   stmt( IRStmt_Put( OFFB_FC3210, e ) );
3490bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj}
3491207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3492893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj/* --------- Get/put the FPU rounding mode. --------- */
3493d01a9639811cd74b608f3d8877af4ad74d5089a7sewardjstatic IRExpr* /* :: Ity_I32 */ get_fpround ( void )
34948f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj{
3495d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj   return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
34968f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj}
34978f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj
3498d01a9639811cd74b608f3d8877af4ad74d5089a7sewardjstatic void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
34998f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj{
3500d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj   stmt( IRStmt_Put( OFFB_FPROUND, e ) );
35018f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj}
35028f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj
35038f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj
3504893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
35058f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj/* Produces a value in 0 .. 3, which is encoded as per the type
3506d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj   IRRoundingMode.  Since the guest_FPROUND value is also encoded as
3507d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj   per IRRoundingMode, we merely need to get it and mask it for
3508d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj   safety.
35098f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj*/
35108f3debf52b76a050bc84997a0358c4aa86dfc88dsewardjstatic IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
35118f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj{
3512d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj   return binop( Iop_And32, get_fpround(), mkU32(3) );
35138f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj}
35148f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj
3515f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardjstatic IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
3516f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj{
3517f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj   return mkU32(Irrm_NEAREST);
3518f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj}
3519f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj
35208f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj
3521207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* --------- Get/set FP register tag bytes. --------- */
3522207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3523207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3524207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3525207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic void put_ST_TAG ( Int i, IRExpr* value )
3526207557ab2ea38239b670785c976b89d50bbb0eccsewardj{
3527dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRRegArray* descr;
3528dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_I8);
3529dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
3530d6f38b3f822f7d57adfc0da3410995d85d6a4597florian   stmt( IRStmt_PutI( mkIRPutI(descr, get_ftop(), i, value) ) );
3531207557ab2ea38239b670785c976b89d50bbb0eccsewardj}
3532207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3533207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Given i, generate an expression yielding 'ST_TAG(i)'.  This will be
3534db199620ca3945e9f43d4738c159ce1860142a55sewardj   zero to indicate "Empty" and nonzero to indicate "NonEmpty".  */
3535207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3536207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic IRExpr* get_ST_TAG ( Int i )
3537d1725d18b61bf7912a9099686179faef5815dba1sewardj{
3538dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
35392d3f77c12d2911173fd182d0b6e954196dee9135sewardj   return IRExpr_GetI( descr, get_ftop(), i );
3540d1725d18b61bf7912a9099686179faef5815dba1sewardj}
3541d1725d18b61bf7912a9099686179faef5815dba1sewardj
3542207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3543207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* --------- Get/set FP registers. --------- */
3544207557ab2ea38239b670785c976b89d50bbb0eccsewardj
35452d3f77c12d2911173fd182d0b6e954196dee9135sewardj/* Given i, and some expression e, emit 'ST(i) = e' and set the
35462d3f77c12d2911173fd182d0b6e954196dee9135sewardj   register's tag to indicate the register is full.  The previous
35472d3f77c12d2911173fd182d0b6e954196dee9135sewardj   state of the register is not checked. */
3548207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3549207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic void put_ST_UNCHECKED ( Int i, IRExpr* value )
3550d1725d18b61bf7912a9099686179faef5815dba1sewardj{
3551dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRRegArray* descr;
3552dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_F64);
3553dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
3554d6f38b3f822f7d57adfc0da3410995d85d6a4597florian   stmt( IRStmt_PutI( mkIRPutI(descr, get_ftop(), i, value) ) );
3555207557ab2ea38239b670785c976b89d50bbb0eccsewardj   /* Mark the register as in-use. */
3556207557ab2ea38239b670785c976b89d50bbb0eccsewardj   put_ST_TAG(i, mkU8(1));
3557d1725d18b61bf7912a9099686179faef5815dba1sewardj}
3558d1725d18b61bf7912a9099686179faef5815dba1sewardj
3559207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Given i, and some expression e, emit
3560207557ab2ea38239b670785c976b89d50bbb0eccsewardj      ST(i) = is_full(i) ? NaN : e
3561207557ab2ea38239b670785c976b89d50bbb0eccsewardj   and set the tag accordingly.
3562207557ab2ea38239b670785c976b89d50bbb0eccsewardj*/
3563207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3564207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic void put_ST ( Int i, IRExpr* value )
3565207557ab2ea38239b670785c976b89d50bbb0eccsewardj{
3566009230b9758291b594e60d7c0243a73d53e81854sewardj   put_ST_UNCHECKED(
3567009230b9758291b594e60d7c0243a73d53e81854sewardj      i,
356899dd03e04a6914d90d5fee727d61d76905334becflorian      IRExpr_ITE( binop(Iop_CmpNE8, get_ST_TAG(i), mkU8(0)),
356999dd03e04a6914d90d5fee727d61d76905334becflorian                  /* non-0 means full */
357099dd03e04a6914d90d5fee727d61d76905334becflorian                  mkQNaN64(),
357199dd03e04a6914d90d5fee727d61d76905334becflorian                  /* 0 means empty */
357299dd03e04a6914d90d5fee727d61d76905334becflorian                  value
3573009230b9758291b594e60d7c0243a73d53e81854sewardj      )
3574207557ab2ea38239b670785c976b89d50bbb0eccsewardj   );
3575207557ab2ea38239b670785c976b89d50bbb0eccsewardj}
3576207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3577207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3578d1725d18b61bf7912a9099686179faef5815dba1sewardj/* Given i, generate an expression yielding 'ST(i)'. */
3579d1725d18b61bf7912a9099686179faef5815dba1sewardj
3580207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic IRExpr* get_ST_UNCHECKED ( Int i )
3581d1725d18b61bf7912a9099686179faef5815dba1sewardj{
3582dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRRegArray* descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
35832d3f77c12d2911173fd182d0b6e954196dee9135sewardj   return IRExpr_GetI( descr, get_ftop(), i );
3584d1725d18b61bf7912a9099686179faef5815dba1sewardj}
3585d1725d18b61bf7912a9099686179faef5815dba1sewardj
3586c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj
3587207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Given i, generate an expression yielding
3588207557ab2ea38239b670785c976b89d50bbb0eccsewardj  is_full(i) ? ST(i) : NaN
3589207557ab2ea38239b670785c976b89d50bbb0eccsewardj*/
3590d1725d18b61bf7912a9099686179faef5815dba1sewardj
3591207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic IRExpr* get_ST ( Int i )
3592d1725d18b61bf7912a9099686179faef5815dba1sewardj{
3593d1725d18b61bf7912a9099686179faef5815dba1sewardj   return
359499dd03e04a6914d90d5fee727d61d76905334becflorian      IRExpr_ITE( binop(Iop_CmpNE8, get_ST_TAG(i), mkU8(0)),
359599dd03e04a6914d90d5fee727d61d76905334becflorian                  /* non-0 means full */
359699dd03e04a6914d90d5fee727d61d76905334becflorian                  get_ST_UNCHECKED(i),
359799dd03e04a6914d90d5fee727d61d76905334becflorian                  /* 0 means empty */
359899dd03e04a6914d90d5fee727d61d76905334becflorian                  mkQNaN64());
3599d1725d18b61bf7912a9099686179faef5815dba1sewardj}
3600d1725d18b61bf7912a9099686179faef5815dba1sewardj
3601a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
3602e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj/* Given i, and some expression e, and a condition cond, generate IR
3603e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   which has the same effect as put_ST(i,e) when cond is true and has
3604e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   no effect when cond is false.  Given the lack of proper
3605e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   if-then-else in the IR, this is pretty tricky.
3606e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj*/
3607e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3608e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardjstatic void maybe_put_ST ( IRTemp cond, Int i, IRExpr* value )
3609e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj{
3610e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   // new_tag = if cond then FULL else old_tag
3611e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   // new_val = if cond then (if old_tag==FULL then NaN else val)
3612e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   //                   else old_val
3613e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3614e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp old_tag = newTemp(Ity_I8);
3615e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(old_tag, get_ST_TAG(i));
3616e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp new_tag = newTemp(Ity_I8);
3617e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(new_tag,
3618e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj          IRExpr_ITE(mkexpr(cond), mkU8(1)/*FULL*/, mkexpr(old_tag)));
3619e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3620e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp old_val = newTemp(Ity_F64);
3621e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(old_val, get_ST_UNCHECKED(i));
3622e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp new_val = newTemp(Ity_F64);
3623e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(new_val,
3624e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj          IRExpr_ITE(mkexpr(cond),
3625e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     IRExpr_ITE(binop(Iop_CmpNE8, mkexpr(old_tag), mkU8(0)),
3626e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                                /* non-0 means full */
3627e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                                mkQNaN64(),
3628e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                                /* 0 means empty */
3629e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                                value),
3630e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(old_val)));
3631e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3632e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   put_ST_UNCHECKED(i, mkexpr(new_val));
3633e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   // put_ST_UNCHECKED incorrectly sets tag(i) to always be FULL.  So
3634e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   // now set it to new_tag instead.
3635e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   put_ST_TAG(i, mkexpr(new_tag));
3636e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj}
3637e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3638207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Adjust FTOP downwards by one register. */
3639207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3640207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic void fp_push ( void )
3641a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj{
36422d3f77c12d2911173fd182d0b6e954196dee9135sewardj   put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
3643a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj}
3644a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
3645e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj/* Adjust FTOP downwards by one register when COND is 1:I1.  Else
3646e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   don't change it. */
3647e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3648e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardjstatic void maybe_fp_push ( IRTemp cond )
3649e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj{
3650e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   put_ftop( binop(Iop_Sub32, get_ftop(), unop(Iop_1Uto32,mkexpr(cond))) );
3651e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj}
3652e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3653207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Adjust FTOP upwards by one register, and mark the vacated register
3654207557ab2ea38239b670785c976b89d50bbb0eccsewardj   as empty.  */
3655207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3656207557ab2ea38239b670785c976b89d50bbb0eccsewardjstatic void fp_pop ( void )
3657207557ab2ea38239b670785c976b89d50bbb0eccsewardj{
3658db199620ca3945e9f43d4738c159ce1860142a55sewardj   put_ST_TAG(0, mkU8(0));
36592d3f77c12d2911173fd182d0b6e954196dee9135sewardj   put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
3660207557ab2ea38239b670785c976b89d50bbb0eccsewardj}
3661207557ab2ea38239b670785c976b89d50bbb0eccsewardj
3662e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj/* Set the C2 bit of the FPU status register to e[0].  Assumes that
3663e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   e[31:1] == 0.
3664e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj*/
3665e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardjstatic void set_C2 ( IRExpr* e )
3666e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj{
3667e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRExpr* cleared = binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2));
3668e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   put_C3210( binop(Iop_Or32,
3669e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                    cleared,
3670e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                    binop(Iop_Shl32, e, mkU8(X86G_FC_SHIFT_C2))) );
3671e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj}
3672e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3673e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj/* Generate code to check that abs(d64) < 2^63 and is finite.  This is
3674e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   used to do the range checks for FSIN, FCOS, FSINCOS and FPTAN.  The
3675e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   test is simple, but the derivation of it is not so simple.
3676e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3677e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   The exponent field for an IEEE754 double is 11 bits.  That means it
3678e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   can take values 0 through 0x7FF.  If the exponent has value 0x7FF,
3679e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   the number is either a NaN or an Infinity and so is not finite.
3680e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   Furthermore, a finite value of exactly 2^63 is the smallest value
3681e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   that has exponent value 0x43E.  Hence, what we need to do is
3682e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   extract the exponent, ignoring the sign bit and mantissa, and check
3683e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   it is < 0x43E, or <= 0x43D.
3684e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj
3685e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   To make this easily applicable to 32- and 64-bit targets, a
3686e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   roundabout approach is used.  First the number is converted to I64,
3687e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   then the top 32 bits are taken.  Shifting them right by 20 bits
3688e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   places the sign bit and exponent in the bottom 12 bits.  Anding
3689e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   with 0x7FF gets rid of the sign bit, leaving just the exponent
3690e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   available for comparison.
3691e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj*/
3692e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardjstatic IRTemp math_IS_TRIG_ARG_FINITE_AND_IN_RANGE ( IRTemp d64 )
36933f61ddbfeb5ec1633b4ede7e4a057a7e77d9c9a4sewardj{
3694e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp i64 = newTemp(Ity_I64);
3695e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(i64, unop(Iop_ReinterpF64asI64, mkexpr(d64)) );
3696e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp exponent = newTemp(Ity_I32);
3697e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(exponent,
3698e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj          binop(Iop_And32,
3699e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                binop(Iop_Shr32, unop(Iop_64HIto32, mkexpr(i64)), mkU8(20)),
3700e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                mkU32(0x7FF)));
3701e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   IRTemp in_range_and_finite = newTemp(Ity_I1);
3702e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   assign(in_range_and_finite,
3703e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj          binop(Iop_CmpLE32U, mkexpr(exponent), mkU32(0x43D)));
3704e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj   return in_range_and_finite;
37053f61ddbfeb5ec1633b4ede7e4a057a7e77d9c9a4sewardj}
37063f61ddbfeb5ec1633b4ede7e4a057a7e77d9c9a4sewardj
3707d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj/* Invent a plausible-looking FPU status word value:
3708d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj      ((ftop & 7) << 11) | (c3210 & 0x4700)
3709d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj */
3710d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardjstatic IRExpr* get_FPU_sw ( void )
3711d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj{
3712d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj   return
3713d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj      unop(Iop_32to16,
3714d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj           binop(Iop_Or32,
3715d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj                 binop(Iop_Shl32,
3716d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj                       binop(Iop_And32, get_ftop(), mkU32(7)),
3717d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj                             mkU8(11)),
3718d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj                       binop(Iop_And32, get_C3210(), mkU32(0x4700))
3719d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj      ));
3720d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj}
3721d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj
37223f61ddbfeb5ec1633b4ede7e4a057a7e77d9c9a4sewardj
3723207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* ------------------------------------------------------- */
3724207557ab2ea38239b670785c976b89d50bbb0eccsewardj/* Given all that stack-mangling junk, we can now go ahead
3725207557ab2ea38239b670785c976b89d50bbb0eccsewardj   and describe FP instructions.
3726207557ab2ea38239b670785c976b89d50bbb0eccsewardj*/
3727207557ab2ea38239b670785c976b89d50bbb0eccsewardj
37283fd5e570294226c643f974b438225e3f09a82f4fsewardj/* ST(0) = ST(0) `op` mem64/32(addr)
3729207557ab2ea38239b670785c976b89d50bbb0eccsewardj   Need to check ST(0)'s tag on read, but not on write.
3730207557ab2ea38239b670785c976b89d50bbb0eccsewardj*/
3731a58ea668d4725b87a146cf43cc48b8ea6ead84casewardjstatic
373255085f8680acc89d727e321f3b34cae1a8c4093aflorianvoid fp_do_op_mem_ST_0 ( IRTemp addr, const HChar* op_txt, HChar* dis_buf,
3733a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj                         IROp op, Bool dbl )
3734a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj{
373533dd31b1bcc175495b96222fa278062fd6116899sewardj   DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
3736a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj   if (dbl) {
37373fd5e570294226c643f974b438225e3f09a82f4fsewardj      put_ST_UNCHECKED(0,
3738f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj         triop( op,
3739f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
37403fd5e570294226c643f974b438225e3f09a82f4fsewardj                get_ST(0),
37413fd5e570294226c643f974b438225e3f09a82f4fsewardj                loadLE(Ity_F64,mkexpr(addr))
37423fd5e570294226c643f974b438225e3f09a82f4fsewardj         ));
3743a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj   } else {
37443fd5e570294226c643f974b438225e3f09a82f4fsewardj      put_ST_UNCHECKED(0,
3745f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj         triop( op,
3746f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
37473fd5e570294226c643f974b438225e3f09a82f4fsewardj                get_ST(0),
37483fd5e570294226c643f974b438225e3f09a82f4fsewardj                unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
37493fd5e570294226c643f974b438225e3f09a82f4fsewardj         ));
37503fd5e570294226c643f974b438225e3f09a82f4fsewardj   }
37513fd5e570294226c643f974b438225e3f09a82f4fsewardj}
37523fd5e570294226c643f974b438225e3f09a82f4fsewardj
37533fd5e570294226c643f974b438225e3f09a82f4fsewardj
37543fd5e570294226c643f974b438225e3f09a82f4fsewardj/* ST(0) = mem64/32(addr) `op` ST(0)
37553fd5e570294226c643f974b438225e3f09a82f4fsewardj   Need to check ST(0)'s tag on read, but not on write.
37563fd5e570294226c643f974b438225e3f09a82f4fsewardj*/
37573fd5e570294226c643f974b438225e3f09a82f4fsewardjstatic
375855085f8680acc89d727e321f3b34cae1a8c4093aflorianvoid fp_do_oprev_mem_ST_0 ( IRTemp addr, const HChar* op_txt, HChar* dis_buf,
3759883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                            IROp op, Bool dbl )
37603fd5e570294226c643f974b438225e3f09a82f4fsewardj{
376133dd31b1bcc175495b96222fa278062fd6116899sewardj   DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
37623fd5e570294226c643f974b438225e3f09a82f4fsewardj   if (dbl) {
37633fd5e570294226c643f974b438225e3f09a82f4fsewardj      put_ST_UNCHECKED(0,
3764f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj         triop( op,
3765f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
37663fd5e570294226c643f974b438225e3f09a82f4fsewardj                loadLE(Ity_F64,mkexpr(addr)),
37673fd5e570294226c643f974b438225e3f09a82f4fsewardj                get_ST(0)
37683fd5e570294226c643f974b438225e3f09a82f4fsewardj         ));
37693fd5e570294226c643f974b438225e3f09a82f4fsewardj   } else {
37703fd5e570294226c643f974b438225e3f09a82f4fsewardj      put_ST_UNCHECKED(0,
3771f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj         triop( op,
3772f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
37733fd5e570294226c643f974b438225e3f09a82f4fsewardj                unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
37743fd5e570294226c643f974b438225e3f09a82f4fsewardj                get_ST(0)
37753fd5e570294226c643f974b438225e3f09a82f4fsewardj         ));
3776a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj   }
3777a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj}
3778a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
3779d1725d18b61bf7912a9099686179faef5815dba1sewardj
3780db199620ca3945e9f43d4738c159ce1860142a55sewardj/* ST(dst) = ST(dst) `op` ST(src).
3781db199620ca3945e9f43d4738c159ce1860142a55sewardj   Check dst and src tags when reading but not on write.
3782db199620ca3945e9f43d4738c159ce1860142a55sewardj*/
3783db199620ca3945e9f43d4738c159ce1860142a55sewardjstatic
378455085f8680acc89d727e321f3b34cae1a8c4093aflorianvoid fp_do_op_ST_ST ( const HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
3785bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj                      Bool pop_after )
3786db199620ca3945e9f43d4738c159ce1860142a55sewardj{
37872d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj   DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
37882d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj                                 (Int)st_src, (Int)st_dst );
3789db199620ca3945e9f43d4738c159ce1860142a55sewardj   put_ST_UNCHECKED(
3790db199620ca3945e9f43d4738c159ce1860142a55sewardj      st_dst,
3791f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj      triop( op,
3792f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj             get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3793f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj             get_ST(st_dst),
3794f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj             get_ST(st_src) )
3795db199620ca3945e9f43d4738c159ce1860142a55sewardj   );
3796bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   if (pop_after)
3797bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      fp_pop();
3798bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj}
3799bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
3800bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj/* ST(dst) = ST(src) `op` ST(dst).
3801bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   Check dst and src tags when reading but not on write.
3802bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj*/
3803bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardjstatic
380455085f8680acc89d727e321f3b34cae1a8c4093aflorianvoid fp_do_oprev_ST_ST ( const HChar* op_txt, IROp op, UInt st_src,
380555085f8680acc89d727e321f3b34cae1a8c4093aflorian                         UInt st_dst, Bool pop_after )
3806bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj{
38072d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj   DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
38082d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj                                 (Int)st_src, (Int)st_dst );
3809bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   put_ST_UNCHECKED(
3810bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      st_dst,
3811f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj      triop( op,
3812f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj             get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3813f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj             get_ST(st_src),
3814f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj             get_ST(st_dst) )
3815bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   );
3816bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   if (pop_after)
3817bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      fp_pop();
3818db199620ca3945e9f43d4738c159ce1860142a55sewardj}
3819db199620ca3945e9f43d4738c159ce1860142a55sewardj
38208308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
38218308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardjstatic void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
38228308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj{
38232d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj   DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", (Int)i );
38248308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj   /* This is a bit of a hack (and isn't really right).  It sets
38258308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj      Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
38268308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj      documentation implies A and S are unchanged.
38278308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj   */
3828feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj   /* It's also fishy in that it is used both for COMIP and
3829feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj      UCOMIP, and they aren't the same (although similar). */
38302a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
38312a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
38322a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP1,
38338308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj                     binop( Iop_And32,
38348308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj                            binop(Iop_CmpF64, get_ST(0), get_ST(i)),
38358308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj                            mkU32(0x45)
38368308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj       )));
3837a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
3838a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      elimination of previous stores to this field work better. */
3839a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
38408308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj   if (pop_after)
38418308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj      fp_pop();
38428308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj}
38438308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
3844db199620ca3945e9f43d4738c159ce1860142a55sewardj
3845d1725d18b61bf7912a9099686179faef5815dba1sewardjstatic
384652d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
3847d1725d18b61bf7912a9099686179faef5815dba1sewardj{
3848a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj   Int    len;
3849a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj   UInt   r_src, r_dst;
3850c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar  dis_buf[50];
385189cd09353a584000edaaa61558b27253bdea7452sewardj   IRTemp t1, t2;
3852d1725d18b61bf7912a9099686179faef5815dba1sewardj
3853d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* On entry, delta points at the second byte of the insn (the modrm
3854d1725d18b61bf7912a9099686179faef5815dba1sewardj      byte).*/
3855d1725d18b61bf7912a9099686179faef5815dba1sewardj   UChar first_opcode = getIByte(delta-1);
3856d1725d18b61bf7912a9099686179faef5815dba1sewardj   UChar modrm        = getIByte(delta+0);
3857d1725d18b61bf7912a9099686179faef5815dba1sewardj
3858d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3859d1725d18b61bf7912a9099686179faef5815dba1sewardj
3860d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xD8) {
3861db199620ca3945e9f43d4738c159ce1860142a55sewardj      if (modrm < 0xC0) {
386289cd09353a584000edaaa61558b27253bdea7452sewardj
386389cd09353a584000edaaa61558b27253bdea7452sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
386489cd09353a584000edaaa61558b27253bdea7452sewardj           specifies an address. */
386589cd09353a584000edaaa61558b27253bdea7452sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
386689cd09353a584000edaaa61558b27253bdea7452sewardj         delta += len;
386789cd09353a584000edaaa61558b27253bdea7452sewardj
386889cd09353a584000edaaa61558b27253bdea7452sewardj         switch (gregOfRM(modrm)) {
386989cd09353a584000edaaa61558b27253bdea7452sewardj
38703fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0: /* FADD single-real */
38713fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
38723fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
38733fd5e570294226c643f974b438225e3f09a82f4fsewardj
387489cd09353a584000edaaa61558b27253bdea7452sewardj            case 1: /* FMUL single-real */
387589cd09353a584000edaaa61558b27253bdea7452sewardj               fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
387689cd09353a584000edaaa61558b27253bdea7452sewardj               break;
387789cd09353a584000edaaa61558b27253bdea7452sewardj
38787ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj            case 2: /* FCOM single-real */
38797ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj               DIP("fcoms %s\n", dis_buf);
38807ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj               /* This forces C1 to zero, which isn't right. */
38817ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj               put_C3210(
38827ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                   binop( Iop_And32,
38837ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                          binop(Iop_Shl32,
38847ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                                binop(Iop_CmpF64,
38857ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                                      get_ST(0),
38867ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                                      unop(Iop_F32toF64,
38877ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                                           loadLE(Ity_F32,mkexpr(addr)))),
38887ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                                mkU8(8)),
38897ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                          mkU32(0x4500)
38907ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj                   ));
38917ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj               break;
38927ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj
38937ca37d92e9596280ac02e86ef59d9133fc0bee47sewardj            case 3: /* FCOMP single-real */
3894e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               DIP("fcomps %s\n", dis_buf);
3895e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               /* This forces C1 to zero, which isn't right. */
3896e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               put_C3210(
3897e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   binop( Iop_And32,
3898e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          binop(Iop_Shl32,
3899e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                binop(Iop_CmpF64,
3900e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                      get_ST(0),
3901e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                      unop(Iop_F32toF64,
3902e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                           loadLE(Ity_F32,mkexpr(addr)))),
3903e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                mkU8(8)),
3904e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          mkU32(0x4500)
3905e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   ));
3906e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               fp_pop();
3907e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               break;
3908e166ed089645c00ea80f732139c22ec2e2c402f1sewardj
3909588ea765122c1ecb97991eea513b12504e35d55esewardj            case 4: /* FSUB single-real */
3910588ea765122c1ecb97991eea513b12504e35d55esewardj               fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3911588ea765122c1ecb97991eea513b12504e35d55esewardj               break;
3912588ea765122c1ecb97991eea513b12504e35d55esewardj
3913588ea765122c1ecb97991eea513b12504e35d55esewardj            case 5: /* FSUBR single-real */
3914588ea765122c1ecb97991eea513b12504e35d55esewardj               fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3915588ea765122c1ecb97991eea513b12504e35d55esewardj               break;
3916588ea765122c1ecb97991eea513b12504e35d55esewardj
3917bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 6: /* FDIV single-real */
3918bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3919bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
3920bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
39218308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            case 7: /* FDIVR single-real */
39228308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
39238308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               break;
39248308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
392589cd09353a584000edaaa61558b27253bdea7452sewardj            default:
392689cd09353a584000edaaa61558b27253bdea7452sewardj               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
392789cd09353a584000edaaa61558b27253bdea7452sewardj               vex_printf("first_opcode == 0xD8\n");
392889cd09353a584000edaaa61558b27253bdea7452sewardj               goto decode_fail;
392989cd09353a584000edaaa61558b27253bdea7452sewardj         }
3930db199620ca3945e9f43d4738c159ce1860142a55sewardj      } else {
3931db199620ca3945e9f43d4738c159ce1860142a55sewardj         delta++;
3932db199620ca3945e9f43d4738c159ce1860142a55sewardj         switch (modrm) {
393389cd09353a584000edaaa61558b27253bdea7452sewardj
3934db199620ca3945e9f43d4738c159ce1860142a55sewardj            case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
3935bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
3936db199620ca3945e9f43d4738c159ce1860142a55sewardj               break;
393789cd09353a584000edaaa61558b27253bdea7452sewardj
39383fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
39393fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
39403fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
39413fd5e570294226c643f974b438225e3f09a82f4fsewardj
3942e166ed089645c00ea80f732139c22ec2e2c402f1sewardj            /* Dunno if this is right */
3943e166ed089645c00ea80f732139c22ec2e2c402f1sewardj            case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3944e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               r_dst = (UInt)modrm - 0xD0;
39452d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fcom %%st(0),%%st(%d)\n", (Int)r_dst);
3946e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               /* This forces C1 to zero, which isn't right. */
3947e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               put_C3210(
3948e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   binop( Iop_And32,
3949e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          binop(Iop_Shl32,
3950e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3951e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                mkU8(8)),
3952e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          mkU32(0x4500)
3953e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   ));
3954e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               break;
39552d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj
395698169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj            /* Dunno if this is right */
395798169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj            case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
395898169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj               r_dst = (UInt)modrm - 0xD8;
39592d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fcomp %%st(0),%%st(%d)\n", (Int)r_dst);
396098169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj               /* This forces C1 to zero, which isn't right. */
396198169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj               put_C3210(
396298169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj                   binop( Iop_And32,
396398169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj                          binop(Iop_Shl32,
396498169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
396598169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj                                mkU8(8)),
396698169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj                          mkU32(0x4500)
396798169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj                   ));
396898169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj               fp_pop();
396998169c5d9d27f3361bf21faf054fa0eb3d9e9d8esewardj               break;
39702d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj
397189cd09353a584000edaaa61558b27253bdea7452sewardj            case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
3972bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
397389cd09353a584000edaaa61558b27253bdea7452sewardj               break;
397489cd09353a584000edaaa61558b27253bdea7452sewardj
39758308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
39768308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
39778308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               break;
39788308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
39793fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
39803fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
39813fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
39823fd5e570294226c643f974b438225e3f09a82f4fsewardj
39833fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
39843fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
39853fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
39863fd5e570294226c643f974b438225e3f09a82f4fsewardj
3987db199620ca3945e9f43d4738c159ce1860142a55sewardj            default:
3988db199620ca3945e9f43d4738c159ce1860142a55sewardj               goto decode_fail;
3989db199620ca3945e9f43d4738c159ce1860142a55sewardj         }
3990db199620ca3945e9f43d4738c159ce1860142a55sewardj      }
3991d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
3992d1725d18b61bf7912a9099686179faef5815dba1sewardj
3993d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3994d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
3995d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xD9) {
3996bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj      if (modrm < 0xC0) {
399789cd09353a584000edaaa61558b27253bdea7452sewardj
399889cd09353a584000edaaa61558b27253bdea7452sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
3999feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            specifies an address. */
400089cd09353a584000edaaa61558b27253bdea7452sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
400189cd09353a584000edaaa61558b27253bdea7452sewardj         delta += len;
400289cd09353a584000edaaa61558b27253bdea7452sewardj
400389cd09353a584000edaaa61558b27253bdea7452sewardj         switch (gregOfRM(modrm)) {
400489cd09353a584000edaaa61558b27253bdea7452sewardj
400589cd09353a584000edaaa61558b27253bdea7452sewardj            case 0: /* FLD single-real */
400633dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("flds %s\n", dis_buf);
400789cd09353a584000edaaa61558b27253bdea7452sewardj               fp_push();
400889cd09353a584000edaaa61558b27253bdea7452sewardj               put_ST(0, unop(Iop_F32toF64,
40098f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj                              loadLE(Ity_F32, mkexpr(addr))));
401089cd09353a584000edaaa61558b27253bdea7452sewardj               break;
401189cd09353a584000edaaa61558b27253bdea7452sewardj
4012588ea765122c1ecb97991eea513b12504e35d55esewardj            case 2: /* FST single-real */
401333dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fsts %s\n", dis_buf);
40143bca906f6e715c544eb49c278bedef093c14c0d7sewardj               storeLE(mkexpr(addr),
40153bca906f6e715c544eb49c278bedef093c14c0d7sewardj                       binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4016588ea765122c1ecb97991eea513b12504e35d55esewardj               break;
4017588ea765122c1ecb97991eea513b12504e35d55esewardj
401889cd09353a584000edaaa61558b27253bdea7452sewardj            case 3: /* FSTP single-real */
401933dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fstps %s\n", dis_buf);
40203bca906f6e715c544eb49c278bedef093c14c0d7sewardj               storeLE(mkexpr(addr),
40213bca906f6e715c544eb49c278bedef093c14c0d7sewardj                       binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
40225bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fp_pop();
402389cd09353a584000edaaa61558b27253bdea7452sewardj               break;
402489cd09353a584000edaaa61558b27253bdea7452sewardj
4025d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj            case 4: { /* FLDENV m28 */
40267df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* Uses dirty helper:
40276ef84bed9bb3af22060eb1759788034602bbcc88florian                     VexEmNote x86g_do_FLDENV ( VexGuestX86State*, HWord ) */
40287df596b1e36840e2d74c90aa55589934add61ccfsewardj               IRTemp   ew = newTemp(Ity_I32);
40297df596b1e36840e2d74c90aa55589934add61ccfsewardj               IRDirty* d  = unsafeIRDirty_0_N (
40307df596b1e36840e2d74c90aa55589934add61ccfsewardj                                0/*regparms*/,
40317df596b1e36840e2d74c90aa55589934add61ccfsewardj                                "x86g_dirtyhelper_FLDENV",
40327df596b1e36840e2d74c90aa55589934add61ccfsewardj                                &x86g_dirtyhelper_FLDENV,
40339041956f39c57e265122ed0a71061dea1e554edcflorian                                mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
40347df596b1e36840e2d74c90aa55589934add61ccfsewardj                             );
403574142b8c8d5d3b3db17d744f5d5fb80f548bcf74sewardj               d->tmp   = ew;
40367df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* declare we're reading memory */
40377df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->mFx   = Ifx_Read;
40387df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->mAddr = mkexpr(addr);
40397df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->mSize = 28;
40407df596b1e36840e2d74c90aa55589934add61ccfsewardj
40417df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* declare we're writing guest state */
404246813fc413b6e3c7b0e25525254bdd22a6672588sewardj               d->nFxState = 4;
4043c9069f2908814843e9a4da00da9c8905440195a6sewardj               vex_bzero(&d->fxState, sizeof(d->fxState));
40447df596b1e36840e2d74c90aa55589934add61ccfsewardj
40457df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[0].fx     = Ifx_Write;
40467df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[0].offset = OFFB_FTOP;
40477df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[0].size   = sizeof(UInt);
40487df596b1e36840e2d74c90aa55589934add61ccfsewardj
40497df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[1].fx     = Ifx_Write;
405046813fc413b6e3c7b0e25525254bdd22a6672588sewardj               d->fxState[1].offset = OFFB_FPTAGS;
405146813fc413b6e3c7b0e25525254bdd22a6672588sewardj               d->fxState[1].size   = 8 * sizeof(UChar);
40527df596b1e36840e2d74c90aa55589934add61ccfsewardj
40537df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[2].fx     = Ifx_Write;
405446813fc413b6e3c7b0e25525254bdd22a6672588sewardj               d->fxState[2].offset = OFFB_FPROUND;
405546813fc413b6e3c7b0e25525254bdd22a6672588sewardj               d->fxState[2].size   = sizeof(UInt);
40567df596b1e36840e2d74c90aa55589934add61ccfsewardj
40577df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[3].fx     = Ifx_Write;
405846813fc413b6e3c7b0e25525254bdd22a6672588sewardj               d->fxState[3].offset = OFFB_FC3210;
40597df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[3].size   = sizeof(UInt);
40607df596b1e36840e2d74c90aa55589934add61ccfsewardj
40617df596b1e36840e2d74c90aa55589934add61ccfsewardj               stmt( IRStmt_Dirty(d) );
40627df596b1e36840e2d74c90aa55589934add61ccfsewardj
40637df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* ew contains any emulation warning we may need to
40647df596b1e36840e2d74c90aa55589934add61ccfsewardj                  issue.  If needed, side-exit to the next insn,
40657df596b1e36840e2d74c90aa55589934add61ccfsewardj                  reporting the warning, so that Valgrind's dispatcher
40667df596b1e36840e2d74c90aa55589934add61ccfsewardj                  sees the warning. */
40677df596b1e36840e2d74c90aa55589934add61ccfsewardj               put_emwarn( mkexpr(ew) );
40687df596b1e36840e2d74c90aa55589934add61ccfsewardj               stmt(
40697df596b1e36840e2d74c90aa55589934add61ccfsewardj                  IRStmt_Exit(
40707df596b1e36840e2d74c90aa55589934add61ccfsewardj                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
40717df596b1e36840e2d74c90aa55589934add61ccfsewardj                     Ijk_EmWarn,
4072c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
4073c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     OFFB_EIP
40747df596b1e36840e2d74c90aa55589934add61ccfsewardj                  )
40757df596b1e36840e2d74c90aa55589934add61ccfsewardj               );
40767df596b1e36840e2d74c90aa55589934add61ccfsewardj
407733dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldenv %s\n", dis_buf);
40787df596b1e36840e2d74c90aa55589934add61ccfsewardj               break;
40797df596b1e36840e2d74c90aa55589934add61ccfsewardj            }
40807df596b1e36840e2d74c90aa55589934add61ccfsewardj
4081893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj            case 5: {/* FLDCW */
4082893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               /* The only thing we observe in the control word is the
4083d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                  rounding mode.  Therefore, pass the 16-bit value
4084d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                  (x87 native-format control word) to a clean helper,
4085d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                  getting back a 64-bit value, the lower half of which
4086d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                  is the FPROUND value to store, and the upper half of
4087d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                  which is the emulation-warning token which may be
4088d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                  generated.
4089893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               */
4090893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               /* ULong x86h_check_fldcw ( UInt ); */
4091893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               IRTemp t64 = newTemp(Ity_I64);
4092893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               IRTemp ew = newTemp(Ity_I32);
409333dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldcw %s\n", dis_buf);
4094893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               assign( t64, mkIRExprCCall(
4095893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                               Ity_I64, 0/*regparms*/,
40963bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                               "x86g_check_fldcw",
40973bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                               &x86g_check_fldcw,
4098893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                               mkIRExprVec_1(
4099893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                                  unop( Iop_16Uto32,
4100893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                                        loadLE(Ity_I16, mkexpr(addr)))
4101893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                               )
4102893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                            )
4103893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                     );
4104893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj
4105d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj               put_fpround( unop(Iop_64to32, mkexpr(t64)) );
4106893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
4107893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               put_emwarn( mkexpr(ew) );
4108893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               /* Finally, if an emulation warning was reported,
4109893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  side-exit to the next insn, reporting the warning,
4110893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  so that Valgrind's dispatcher sees the warning. */
4111893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               stmt(
4112893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  IRStmt_Exit(
4113893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4114893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                     Ijk_EmWarn,
4115c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
4116c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     OFFB_EIP
4117893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  )
4118893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               );
411989cd09353a584000edaaa61558b27253bdea7452sewardj               break;
4120893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj            }
412189cd09353a584000edaaa61558b27253bdea7452sewardj
41227df596b1e36840e2d74c90aa55589934add61ccfsewardj            case 6: { /* FNSTENV m28 */
41237df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* Uses dirty helper:
41244017a3b223ee0ae98f6068e5eaaee0e3151d482asewardj                     void x86g_do_FSTENV ( VexGuestX86State*, HWord ) */
41257df596b1e36840e2d74c90aa55589934add61ccfsewardj               IRDirty* d = unsafeIRDirty_0_N (
41267df596b1e36840e2d74c90aa55589934add61ccfsewardj                               0/*regparms*/,
41277df596b1e36840e2d74c90aa55589934add61ccfsewardj                               "x86g_dirtyhelper_FSTENV",
41287df596b1e36840e2d74c90aa55589934add61ccfsewardj                               &x86g_dirtyhelper_FSTENV,
41299041956f39c57e265122ed0a71061dea1e554edcflorian                               mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
41307df596b1e36840e2d74c90aa55589934add61ccfsewardj                            );
41317df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* declare we're writing memory */
41327df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->mFx   = Ifx_Write;
41337df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->mAddr = mkexpr(addr);
41347df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->mSize = 28;
41357df596b1e36840e2d74c90aa55589934add61ccfsewardj
41367df596b1e36840e2d74c90aa55589934add61ccfsewardj               /* declare we're reading guest state */
41377df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->nFxState = 4;
4138c9069f2908814843e9a4da00da9c8905440195a6sewardj               vex_bzero(&d->fxState, sizeof(d->fxState));
41397df596b1e36840e2d74c90aa55589934add61ccfsewardj
41407df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[0].fx     = Ifx_Read;
41417df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[0].offset = OFFB_FTOP;
41427df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[0].size   = sizeof(UInt);
41437df596b1e36840e2d74c90aa55589934add61ccfsewardj
41447df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[1].fx     = Ifx_Read;
41457df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[1].offset = OFFB_FPTAGS;
41467df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[1].size   = 8 * sizeof(UChar);
41477df596b1e36840e2d74c90aa55589934add61ccfsewardj
41487df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[2].fx     = Ifx_Read;
41497df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[2].offset = OFFB_FPROUND;
41507df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[2].size   = sizeof(UInt);
41517df596b1e36840e2d74c90aa55589934add61ccfsewardj
41527df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[3].fx     = Ifx_Read;
41537df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[3].offset = OFFB_FC3210;
41547df596b1e36840e2d74c90aa55589934add61ccfsewardj               d->fxState[3].size   = sizeof(UInt);
41557df596b1e36840e2d74c90aa55589934add61ccfsewardj
41567df596b1e36840e2d74c90aa55589934add61ccfsewardj               stmt( IRStmt_Dirty(d) );
41577df596b1e36840e2d74c90aa55589934add61ccfsewardj
415833dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fnstenv %s\n", dis_buf);
41597df596b1e36840e2d74c90aa55589934add61ccfsewardj               break;
41607df596b1e36840e2d74c90aa55589934add61ccfsewardj            }
41617df596b1e36840e2d74c90aa55589934add61ccfsewardj
4162588ea765122c1ecb97991eea513b12504e35d55esewardj            case 7: /* FNSTCW */
4163893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj              /* Fake up a native x87 FPU control word.  The only
4164d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                 thing it depends on is FPROUND[1:0], so call a clean
4165893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                 helper to cook it up. */
4166d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj               /* UInt x86h_create_fpucw ( UInt fpround ) */
416733dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fnstcw %s\n", dis_buf);
4168893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               storeLE(
4169893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  mkexpr(addr),
4170893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  unop( Iop_32to16,
4171893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                        mkIRExprCCall(
4172893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                           Ity_I32, 0/*regp*/,
41733bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                           "x86g_create_fpucw", &x86g_create_fpucw,
4174d01a9639811cd74b608f3d8877af4ad74d5089a7sewardj                           mkIRExprVec_1( get_fpround() )
4175893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                        )
4176893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  )
4177893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               );
417889cd09353a584000edaaa61558b27253bdea7452sewardj               break;
417989cd09353a584000edaaa61558b27253bdea7452sewardj
418089cd09353a584000edaaa61558b27253bdea7452sewardj            default:
418189cd09353a584000edaaa61558b27253bdea7452sewardj               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
418289cd09353a584000edaaa61558b27253bdea7452sewardj               vex_printf("first_opcode == 0xD9\n");
418389cd09353a584000edaaa61558b27253bdea7452sewardj               goto decode_fail;
418489cd09353a584000edaaa61558b27253bdea7452sewardj         }
418589cd09353a584000edaaa61558b27253bdea7452sewardj
4186bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj      } else {
4187bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         delta++;
4188bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         switch (modrm) {
418989cd09353a584000edaaa61558b27253bdea7452sewardj
4190bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj            case 0xC0 ... 0xC7: /* FLD %st(?) */
4191a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               r_src = (UInt)modrm - 0xC0;
41922d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fld %%st(%d)\n", (Int)r_src);
41935bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               t1 = newTemp(Ity_F64);
41945bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               assign(t1, get_ST(r_src));
41955bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fp_push();
41965bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               put_ST(0, mkexpr(t1));
4197bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               break;
4198bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj
419989cd09353a584000edaaa61558b27253bdea7452sewardj            case 0xC8 ... 0xCF: /* FXCH %st(?) */
420089cd09353a584000edaaa61558b27253bdea7452sewardj               r_src = (UInt)modrm - 0xC8;
42012d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fxch %%st(%d)\n", (Int)r_src);
420289cd09353a584000edaaa61558b27253bdea7452sewardj               t1 = newTemp(Ity_F64);
420389cd09353a584000edaaa61558b27253bdea7452sewardj               t2 = newTemp(Ity_F64);
420489cd09353a584000edaaa61558b27253bdea7452sewardj               assign(t1, get_ST(0));
420589cd09353a584000edaaa61558b27253bdea7452sewardj               assign(t2, get_ST(r_src));
420689cd09353a584000edaaa61558b27253bdea7452sewardj               put_ST_UNCHECKED(0, mkexpr(t2));
420789cd09353a584000edaaa61558b27253bdea7452sewardj               put_ST_UNCHECKED(r_src, mkexpr(t1));
420889cd09353a584000edaaa61558b27253bdea7452sewardj               break;
420989cd09353a584000edaaa61558b27253bdea7452sewardj
4210cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 0xE0: /* FCHS */
4211cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               DIP("fchs\n");
4212cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4213cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4214cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
4215883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 0xE1: /* FABS */
4216883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               DIP("fabs\n");
4217883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4218883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               break;
4219883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
42201c31877a29646fb6f902de217ae8f62bccfeda7dsewardj            case 0xE4: /* FTST */
42211c31877a29646fb6f902de217ae8f62bccfeda7dsewardj               DIP("ftst\n");
42221c31877a29646fb6f902de217ae8f62bccfeda7dsewardj               /* This forces C1 to zero, which isn't right. */
42231c31877a29646fb6f902de217ae8f62bccfeda7dsewardj               /* Well, in fact the Intel docs say (bizarrely): "C1 is
42241c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                  set to 0 if stack underflow occurred; otherwise, set
42251c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                  to 0" which is pretty nonsensical.  I guess it's a
42261c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                   typo. */
42271c31877a29646fb6f902de217ae8f62bccfeda7dsewardj               put_C3210(
42281c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                   binop( Iop_And32,
42291c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                          binop(Iop_Shl32,
42301c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                                binop(Iop_CmpF64,
42311c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                                      get_ST(0),
42321c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                                      IRExpr_Const(IRConst_F64i(0x0ULL))),
42331c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                                mkU8(8)),
42341c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                          mkU32(0x4500)
42351c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                   ));
42361c31877a29646fb6f902de217ae8f62bccfeda7dsewardj               break;
42371c31877a29646fb6f902de217ae8f62bccfeda7dsewardj
4238883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 0xE5: { /* FXAM */
4239883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               /* This is an interesting one.  It examines %st(0),
4240883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                  regardless of whether the tag says it's empty or not.
4241883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                  Here, just pass both the tag (in our format) and the
4242883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                  value (as a double, actually a ULong) to a helper
4243883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                  function. */
4244f96552617c82834ece36184e674e249faa899b2fsewardj               IRExpr** args
4245f96552617c82834ece36184e674e249faa899b2fsewardj                  = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
4246f96552617c82834ece36184e674e249faa899b2fsewardj                                   unop(Iop_ReinterpF64asI64,
4247f96552617c82834ece36184e674e249faa899b2fsewardj                                        get_ST_UNCHECKED(0)) );
4248f96552617c82834ece36184e674e249faa899b2fsewardj               put_C3210(mkIRExprCCall(
42498ea867b06de73d909c29e243407713c291c8414esewardj                            Ity_I32,
4250f96552617c82834ece36184e674e249faa899b2fsewardj                            0/*regparm*/,
42512a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                            "x86g_calculate_FXAM", &x86g_calculate_FXAM,
42528ea867b06de73d909c29e243407713c291c8414esewardj                            args
42538ea867b06de73d909c29e243407713c291c8414esewardj                        ));
425433dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fxam\n");
4255883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               break;
4256883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            }
4257883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
4258883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 0xE8: /* FLD1 */
425933dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fld1\n");
4260ce646f23d71ac432c340667387aa4a5ce7d18099sewardj               fp_push();
42619c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
42629c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
4263ce646f23d71ac432c340667387aa4a5ce7d18099sewardj               break;
4264ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
426537158719b222a3776df257a80c8ce44d810fae82sewardj            case 0xE9: /* FLDL2T */
426633dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldl2t\n");
426737158719b222a3776df257a80c8ce44d810fae82sewardj               fp_push();
42689c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
42699c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
427037158719b222a3776df257a80c8ce44d810fae82sewardj               break;
427137158719b222a3776df257a80c8ce44d810fae82sewardj
42728308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            case 0xEA: /* FLDL2E */
427333dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldl2e\n");
42748308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               fp_push();
42759c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
42769c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
42778308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               break;
42788308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
4279a0d48d648efc6948d5319c5b22705b397ac664b6sewardj            case 0xEB: /* FLDPI */
428033dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldpi\n");
4281a0d48d648efc6948d5319c5b22705b397ac664b6sewardj               fp_push();
42829c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
42839c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
4284a0d48d648efc6948d5319c5b22705b397ac664b6sewardj               break;
4285a0d48d648efc6948d5319c5b22705b397ac664b6sewardj
4286db199620ca3945e9f43d4738c159ce1860142a55sewardj            case 0xEC: /* FLDLG2 */
428733dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldlg2\n");
4288db199620ca3945e9f43d4738c159ce1860142a55sewardj               fp_push();
42899c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
42909c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
4291db199620ca3945e9f43d4738c159ce1860142a55sewardj               break;
4292db199620ca3945e9f43d4738c159ce1860142a55sewardj
4293db199620ca3945e9f43d4738c159ce1860142a55sewardj            case 0xED: /* FLDLN2 */
429433dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldln2\n");
4295db199620ca3945e9f43d4738c159ce1860142a55sewardj               fp_push();
42969c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
42979c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
4298db199620ca3945e9f43d4738c159ce1860142a55sewardj               break;
4299db199620ca3945e9f43d4738c159ce1860142a55sewardj
4300a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj            case 0xEE: /* FLDZ */
430133dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldz\n");
4302207557ab2ea38239b670785c976b89d50bbb0eccsewardj               fp_push();
43039c323769234fcbd5b08c8747dc4625621bf814ecsewardj               /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
43049c323769234fcbd5b08c8747dc4625621bf814ecsewardj               put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
4305a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               break;
4306a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
430706c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj            case 0xF0: /* F2XM1 */
430806c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               DIP("f2xm1\n");
4309f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj               put_ST_UNCHECKED(0,
4310f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  binop(Iop_2xm1F64,
4311f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4312f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(0)));
431306c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               break;
431406c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj
431552ace3ed99ccb7d0e4c64dc06381e407a8bfcf1dsewardj            case 0xF1: /* FYL2X */
431652ace3ed99ccb7d0e4c64dc06381e407a8bfcf1dsewardj               DIP("fyl2x\n");
4317f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj               put_ST_UNCHECKED(1,
4318f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(Iop_Yl2xF64,
4319f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4320f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(1),
4321f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(0)));
432252ace3ed99ccb7d0e4c64dc06381e407a8bfcf1dsewardj               fp_pop();
432352ace3ed99ccb7d0e4c64dc06381e407a8bfcf1dsewardj               break;
432452ace3ed99ccb7d0e4c64dc06381e407a8bfcf1dsewardj
4325e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj            case 0xF2: { /* FPTAN */
4326e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               DIP("fptan\n");
4327e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp argD = newTemp(Ity_F64);
4328e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               assign(argD, get_ST(0));
4329e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4330e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp resD = newTemp(Ity_F64);
4331e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               assign(resD,
4332e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                  IRExpr_ITE(
4333e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(argOK),
4334e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     binop(Iop_TanF64,
4335e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                           get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4336e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                           mkexpr(argD)),
4337e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(argD))
4338e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               );
4339e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               put_ST_UNCHECKED(0, mkexpr(resD));
4340e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               /* Conditionally push 1.0 on the stack, if the arg is
4341e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                  in range */
4342e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               maybe_fp_push(argOK);
4343e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               maybe_put_ST(argOK, 0,
4344e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                            IRExpr_Const(IRConst_F64(1.0)));
4345e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               set_C2( binop(Iop_Xor32,
4346e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                             unop(Iop_1Uto32, mkexpr(argOK)),
4347e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                             mkU32(1)) );
434899016a7b2d31c50a02b4a3ae8c7b0cf4de2c22cfsewardj               break;
4349e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj            }
435099016a7b2d31c50a02b4a3ae8c7b0cf4de2c22cfsewardj
4351cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 0xF3: /* FPATAN */
4352cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               DIP("fpatan\n");
4353f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj               put_ST_UNCHECKED(1,
4354f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(Iop_AtanF64,
4355f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4356f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(1),
4357f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(0)));
4358cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_pop();
4359cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4360cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
4361f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj            case 0xF4: { /* FXTRACT */
4362fda10af6bee6565643e8ff474b828479ba873080sewardj               IRTemp argF = newTemp(Ity_F64);
4363fda10af6bee6565643e8ff474b828479ba873080sewardj               IRTemp sigF = newTemp(Ity_F64);
4364fda10af6bee6565643e8ff474b828479ba873080sewardj               IRTemp expF = newTemp(Ity_F64);
4365fda10af6bee6565643e8ff474b828479ba873080sewardj               IRTemp argI = newTemp(Ity_I64);
4366fda10af6bee6565643e8ff474b828479ba873080sewardj               IRTemp sigI = newTemp(Ity_I64);
4367fda10af6bee6565643e8ff474b828479ba873080sewardj               IRTemp expI = newTemp(Ity_I64);
4368fda10af6bee6565643e8ff474b828479ba873080sewardj               DIP("fxtract\n");
4369fda10af6bee6565643e8ff474b828479ba873080sewardj               assign( argF, get_ST(0) );
4370fda10af6bee6565643e8ff474b828479ba873080sewardj               assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
4371fda10af6bee6565643e8ff474b828479ba873080sewardj               assign( sigI,
4372879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                       mkIRExprCCall(
4373879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          Ity_I64, 0/*regparms*/,
4374879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          "x86amd64g_calculate_FXTRACT",
4375879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          &x86amd64g_calculate_FXTRACT,
4376879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          mkIRExprVec_2( mkexpr(argI),
4377879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                                         mkIRExpr_HWord(0)/*sig*/ ))
4378879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj               );
4379fda10af6bee6565643e8ff474b828479ba873080sewardj               assign( expI,
4380879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                       mkIRExprCCall(
4381879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          Ity_I64, 0/*regparms*/,
4382879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          "x86amd64g_calculate_FXTRACT",
4383879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          &x86amd64g_calculate_FXTRACT,
4384879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                          mkIRExprVec_2( mkexpr(argI),
4385879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj                                         mkIRExpr_HWord(1)/*exp*/ ))
4386879cee079c349fb9e793c910dd9f2ee4947bdb54sewardj               );
4387fda10af6bee6565643e8ff474b828479ba873080sewardj               assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
4388fda10af6bee6565643e8ff474b828479ba873080sewardj               assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
4389fda10af6bee6565643e8ff474b828479ba873080sewardj               /* exponent */
4390fda10af6bee6565643e8ff474b828479ba873080sewardj               put_ST_UNCHECKED(0, mkexpr(expF) );
4391fda10af6bee6565643e8ff474b828479ba873080sewardj               fp_push();
4392fda10af6bee6565643e8ff474b828479ba873080sewardj               /* significand */
4393fda10af6bee6565643e8ff474b828479ba873080sewardj               put_ST(0, mkexpr(sigF) );
4394fda10af6bee6565643e8ff474b828479ba873080sewardj               break;
4395fda10af6bee6565643e8ff474b828479ba873080sewardj            }
4396fda10af6bee6565643e8ff474b828479ba873080sewardj
4397442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj            case 0xF5: { /* FPREM1 -- IEEE compliant */
4398442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               IRTemp a1 = newTemp(Ity_F64);
4399442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               IRTemp a2 = newTemp(Ity_F64);
4400442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               DIP("fprem1\n");
4401442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               /* Do FPREM1 twice, once to get the remainder, and once
4402442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj                  to get the C3210 flag values. */
4403442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               assign( a1, get_ST(0) );
4404442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               assign( a2, get_ST(1) );
4405f47286e34e0d2899b47d64205816866a16a13ba4sewardj               put_ST_UNCHECKED(0,
4406f47286e34e0d2899b47d64205816866a16a13ba4sewardj                  triop(Iop_PRem1F64,
4407f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4408f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a1),
4409f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a2)));
4410f47286e34e0d2899b47d64205816866a16a13ba4sewardj               put_C3210(
4411f47286e34e0d2899b47d64205816866a16a13ba4sewardj                  triop(Iop_PRem1C3210F64,
4412f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4413f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a1),
4414f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a2)) );
4415442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj               break;
4416442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj            }
4417442d0be1e8050056c3f50a8c0f9e74ed1d522c84sewardj
4418feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 0xF7: /* FINCSTP */
4419feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               DIP("fprem\n");
4420feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4421feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               break;
4422feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
442346de4076882d6a44ff0f76bd8b70c3d89b050293sewardj            case 0xF8: { /* FPREM -- not IEEE compliant */
442446de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               IRTemp a1 = newTemp(Ity_F64);
442546de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               IRTemp a2 = newTemp(Ity_F64);
442646de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               DIP("fprem\n");
442746de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               /* Do FPREM twice, once to get the remainder, and once
442846de4076882d6a44ff0f76bd8b70c3d89b050293sewardj                  to get the C3210 flag values. */
442946de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               assign( a1, get_ST(0) );
443046de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               assign( a2, get_ST(1) );
4431f47286e34e0d2899b47d64205816866a16a13ba4sewardj               put_ST_UNCHECKED(0,
4432f47286e34e0d2899b47d64205816866a16a13ba4sewardj                  triop(Iop_PRemF64,
4433f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4434f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a1),
4435f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a2)));
4436f47286e34e0d2899b47d64205816866a16a13ba4sewardj               put_C3210(
4437f47286e34e0d2899b47d64205816866a16a13ba4sewardj                  triop(Iop_PRemC3210F64,
4438f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4439f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a1),
4440f47286e34e0d2899b47d64205816866a16a13ba4sewardj                        mkexpr(a2)) );
444146de4076882d6a44ff0f76bd8b70c3d89b050293sewardj               break;
444246de4076882d6a44ff0f76bd8b70c3d89b050293sewardj            }
444346de4076882d6a44ff0f76bd8b70c3d89b050293sewardj
44448308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            case 0xF9: /* FYL2XP1 */
44458308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               DIP("fyl2xp1\n");
4446f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj               put_ST_UNCHECKED(1,
4447f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(Iop_Yl2xp1F64,
4448f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4449f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(1),
4450f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(0)));
44518308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               fp_pop();
44528308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               break;
44538308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
4454c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj            case 0xFA: /* FSQRT */
4455c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               DIP("fsqrt\n");
4456f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj               put_ST_UNCHECKED(0,
4457f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  binop(Iop_SqrtF64,
4458f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4459f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(0)));
4460c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               break;
4461c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj
4462519d66fc0e4f16b120079bc651862e49f154da62sewardj            case 0xFB: { /* FSINCOS */
4463519d66fc0e4f16b120079bc651862e49f154da62sewardj               DIP("fsincos\n");
4464e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp argD = newTemp(Ity_F64);
4465e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               assign(argD, get_ST(0));
4466e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4467e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp resD = newTemp(Ity_F64);
4468e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               assign(resD,
4469e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                  IRExpr_ITE(
4470e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(argOK),
4471e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     binop(Iop_SinF64,
4472e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                           get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4473e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                           mkexpr(argD)),
4474e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(argD))
4475e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               );
4476e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               put_ST_UNCHECKED(0, mkexpr(resD));
4477e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               /* Conditionally push the cos value on the stack, if
4478e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                  the arg is in range */
4479e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               maybe_fp_push(argOK);
4480e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               maybe_put_ST(argOK, 0,
4481f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  binop(Iop_CosF64,
4482f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4483e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                        mkexpr(argD)));
4484e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               set_C2( binop(Iop_Xor32,
4485e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                             unop(Iop_1Uto32, mkexpr(argOK)),
4486e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                             mkU32(1)) );
4487519d66fc0e4f16b120079bc651862e49f154da62sewardj               break;
4488519d66fc0e4f16b120079bc651862e49f154da62sewardj            }
4489519d66fc0e4f16b120079bc651862e49f154da62sewardj
4490e6709111d4af7becab76be5971eea568074174cdsewardj            case 0xFC: /* FRNDINT */
4491e6709111d4af7becab76be5971eea568074174cdsewardj               DIP("frndint\n");
4492e6709111d4af7becab76be5971eea568074174cdsewardj               put_ST_UNCHECKED(0,
4493b183b8571b4ec98866ce2b3653a9d066cf5f16f4sewardj                  binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
4494e6709111d4af7becab76be5971eea568074174cdsewardj               break;
4495e6709111d4af7becab76be5971eea568074174cdsewardj
449606c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj            case 0xFD: /* FSCALE */
449706c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               DIP("fscale\n");
4498f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj               put_ST_UNCHECKED(0,
4499f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(Iop_ScaleF64,
4500f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4501f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(0),
4502f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_ST(1)));
450306c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               break;
450406c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj
4505e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj            case 0xFE:   /* FSIN */
4506e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj            case 0xFF: { /* FCOS */
4507e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               Bool isSIN = modrm == 0xFE;
4508e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               DIP("%s\n", isSIN ? "fsin" : "fcos");
4509e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp argD = newTemp(Ity_F64);
4510e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               assign(argD, get_ST(0));
4511e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4512e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               IRTemp resD = newTemp(Ity_F64);
4513e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               assign(resD,
4514e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                  IRExpr_ITE(
4515e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(argOK),
4516e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     binop(isSIN ? Iop_SinF64 : Iop_CosF64,
4517e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                           get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4518e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                           mkexpr(argD)),
4519e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                     mkexpr(argD))
4520e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               );
4521e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               put_ST_UNCHECKED(0, mkexpr(resD));
4522e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj               set_C2( binop(Iop_Xor32,
4523e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                             unop(Iop_1Uto32, mkexpr(argOK)),
4524e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj                             mkU32(1)) );
4525cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4526e9c51c9287ce703a0740e610d5bdd2ea8429fb6dsewardj            }
4527cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
4528bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj            default:
4529bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               goto decode_fail;
4530bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         }
4531bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj      }
4532d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
4533d1725d18b61bf7912a9099686179faef5815dba1sewardj
4534d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4535d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
4536d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xDA) {
4537bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj
4538bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj      if (modrm < 0xC0) {
4539bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj
4540feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
4541bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj            specifies an address. */
4542ce646f23d71ac432c340667387aa4a5ce7d18099sewardj         IROp   fop;
4543bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4544bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         delta += len;
4545bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         switch (gregOfRM(modrm)) {
4546ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
4547db199620ca3945e9f43d4738c159ce1860142a55sewardj            case 0: /* FIADD m32int */ /* ST(0) += m32int */
454833dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fiaddl %s\n", dis_buf);
45495bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fop = Iop_AddF64;
45505bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               goto do_fop_m32;
4551db199620ca3945e9f43d4738c159ce1860142a55sewardj
4552207557ab2ea38239b670785c976b89d50bbb0eccsewardj            case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
455333dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fimull %s\n", dis_buf);
45545bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fop = Iop_MulF64;
45555bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               goto do_fop_m32;
4556ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
4557071895fca57b5b710485a4951fef12317e337064sewardj            case 2: /* FICOM m32int */
4558071895fca57b5b710485a4951fef12317e337064sewardj               DIP("ficoml %s\n", dis_buf);
4559071895fca57b5b710485a4951fef12317e337064sewardj               /* This forces C1 to zero, which isn't right. */
4560071895fca57b5b710485a4951fef12317e337064sewardj               put_C3210(
4561071895fca57b5b710485a4951fef12317e337064sewardj                   binop( Iop_And32,
4562071895fca57b5b710485a4951fef12317e337064sewardj                          binop(Iop_Shl32,
4563071895fca57b5b710485a4951fef12317e337064sewardj                                binop(Iop_CmpF64,
4564071895fca57b5b710485a4951fef12317e337064sewardj                                      get_ST(0),
45656c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                                      unop(Iop_I32StoF64,
4566071895fca57b5b710485a4951fef12317e337064sewardj                                           loadLE(Ity_I32,mkexpr(addr)))),
4567071895fca57b5b710485a4951fef12317e337064sewardj                                mkU8(8)),
4568071895fca57b5b710485a4951fef12317e337064sewardj                          mkU32(0x4500)
4569071895fca57b5b710485a4951fef12317e337064sewardj                   ));
4570071895fca57b5b710485a4951fef12317e337064sewardj               break;
4571071895fca57b5b710485a4951fef12317e337064sewardj
4572071895fca57b5b710485a4951fef12317e337064sewardj            case 3: /* FICOMP m32int */
4573071895fca57b5b710485a4951fef12317e337064sewardj               DIP("ficompl %s\n", dis_buf);
4574071895fca57b5b710485a4951fef12317e337064sewardj               /* This forces C1 to zero, which isn't right. */
4575071895fca57b5b710485a4951fef12317e337064sewardj               put_C3210(
4576071895fca57b5b710485a4951fef12317e337064sewardj                   binop( Iop_And32,
4577071895fca57b5b710485a4951fef12317e337064sewardj                          binop(Iop_Shl32,
4578071895fca57b5b710485a4951fef12317e337064sewardj                                binop(Iop_CmpF64,
4579071895fca57b5b710485a4951fef12317e337064sewardj                                      get_ST(0),
45806c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                                      unop(Iop_I32StoF64,
4581071895fca57b5b710485a4951fef12317e337064sewardj                                           loadLE(Ity_I32,mkexpr(addr)))),
4582071895fca57b5b710485a4951fef12317e337064sewardj                                mkU8(8)),
4583071895fca57b5b710485a4951fef12317e337064sewardj                          mkU32(0x4500)
4584071895fca57b5b710485a4951fef12317e337064sewardj                   ));
4585071895fca57b5b710485a4951fef12317e337064sewardj               fp_pop();
4586071895fca57b5b710485a4951fef12317e337064sewardj               break;
4587071895fca57b5b710485a4951fef12317e337064sewardj
4588ce646f23d71ac432c340667387aa4a5ce7d18099sewardj            case 4: /* FISUB m32int */ /* ST(0) -= m32int */
458933dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fisubl %s\n", dis_buf);
45905bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fop = Iop_SubF64;
45915bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               goto do_fop_m32;
4592ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
45938308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
459433dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fisubrl %s\n", dis_buf);
45955bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fop = Iop_SubF64;
45965bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               goto do_foprev_m32;
45978308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
4598ce646f23d71ac432c340667387aa4a5ce7d18099sewardj            case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
459936917e92816cfd8c998e56f774709d953967b2a6sewardj               DIP("fidivl %s\n", dis_buf);
46005bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fop = Iop_DivF64;
46015bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               goto do_fop_m32;
4602ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
4603c4eaff3aa358fc5c73b534c7e78366555184244fsewardj            case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
460433dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fidivrl %s\n", dis_buf);
46055bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fop = Iop_DivF64;
46065bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               goto do_foprev_m32;
4607c4eaff3aa358fc5c73b534c7e78366555184244fsewardj
4608ce646f23d71ac432c340667387aa4a5ce7d18099sewardj            do_fop_m32:
4609207557ab2ea38239b670785c976b89d50bbb0eccsewardj               put_ST_UNCHECKED(0,
4610f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(fop,
4611f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4612207557ab2ea38239b670785c976b89d50bbb0eccsewardj                        get_ST(0),
46136c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        unop(Iop_I32StoF64,
461489cd09353a584000edaaa61558b27253bdea7452sewardj                             loadLE(Ity_I32, mkexpr(addr)))));
4615bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               break;
4616bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj
4617c4eaff3aa358fc5c73b534c7e78366555184244fsewardj            do_foprev_m32:
4618c4eaff3aa358fc5c73b534c7e78366555184244fsewardj               put_ST_UNCHECKED(0,
4619f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(fop,
4620f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
46216c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        unop(Iop_I32StoF64,
4622c4eaff3aa358fc5c73b534c7e78366555184244fsewardj                             loadLE(Ity_I32, mkexpr(addr))),
4623c4eaff3aa358fc5c73b534c7e78366555184244fsewardj                        get_ST(0)));
4624c4eaff3aa358fc5c73b534c7e78366555184244fsewardj               break;
4625c4eaff3aa358fc5c73b534c7e78366555184244fsewardj
4626bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj            default:
4627bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4628bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               vex_printf("first_opcode == 0xDA\n");
4629bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               goto decode_fail;
4630bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         }
46314cb918d355cef4e7640d374346852db4556f3524sewardj
4632bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj      } else {
4633bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
4634bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         delta++;
4635bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         switch (modrm) {
4636bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
4637519d66fc0e4f16b120079bc651862e49f154da62sewardj            case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4638519d66fc0e4f16b120079bc651862e49f154da62sewardj               r_src = (UInt)modrm - 0xC0;
46392d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fcmovb %%st(%d), %%st(0)\n", (Int)r_src);
4640519d66fc0e4f16b120079bc651862e49f154da62sewardj               put_ST_UNCHECKED(0,
464199dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4642009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondB),
464399dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
4644519d66fc0e4f16b120079bc651862e49f154da62sewardj               break;
4645519d66fc0e4f16b120079bc651862e49f154da62sewardj
46463fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
46473fd5e570294226c643f974b438225e3f09a82f4fsewardj               r_src = (UInt)modrm - 0xC8;
46482d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fcmovz %%st(%d), %%st(0)\n", (Int)r_src);
46495bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               put_ST_UNCHECKED(0,
465099dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4651009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondZ),
465299dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
46533fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
46543fd5e570294226c643f974b438225e3f09a82f4fsewardj
4655519d66fc0e4f16b120079bc651862e49f154da62sewardj            case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4656519d66fc0e4f16b120079bc651862e49f154da62sewardj               r_src = (UInt)modrm - 0xD0;
46572d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fcmovbe %%st(%d), %%st(0)\n", (Int)r_src);
4658519d66fc0e4f16b120079bc651862e49f154da62sewardj               put_ST_UNCHECKED(0,
465999dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4660009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondBE),
466199dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
4662519d66fc0e4f16b120079bc651862e49f154da62sewardj               break;
4663519d66fc0e4f16b120079bc651862e49f154da62sewardj
46648253ad3c3696f46b30daf66003f7649abe70286dsewardj            case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
46658253ad3c3696f46b30daf66003f7649abe70286dsewardj               r_src = (UInt)modrm - 0xD8;
4666d8862cf5aedae31e2279546af7cab02dff4287a9sewardj               DIP("fcmovu %%st(%d), %%st(0)\n", (Int)r_src);
46678253ad3c3696f46b30daf66003f7649abe70286dsewardj               put_ST_UNCHECKED(0,
466899dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4669009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondP),
467099dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
46718253ad3c3696f46b30daf66003f7649abe70286dsewardj               break;
46728253ad3c3696f46b30daf66003f7649abe70286dsewardj
4673bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xE9: /* FUCOMPP %st(0),%st(1) */
4674bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               DIP("fucompp %%st(0),%%st(1)\n");
4675c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               /* This forces C1 to zero, which isn't right. */
4676c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               put_C3210(
4677c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                   binop( Iop_And32,
4678c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                          binop(Iop_Shl32,
4679c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                                binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4680c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                                mkU8(8)),
4681c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                          mkU32(0x4500)
4682c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                   ));
4683bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_pop();
4684bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_pop();
4685bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
4686bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
46875bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            default:
4688bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               goto decode_fail;
46895bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         }
4690bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
4691bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj      }
4692d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
4693d1725d18b61bf7912a9099686179faef5815dba1sewardj
4694d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4695d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
4696d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xDB) {
469789cd09353a584000edaaa61558b27253bdea7452sewardj      if (modrm < 0xC0) {
469889cd09353a584000edaaa61558b27253bdea7452sewardj
4699feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
470089cd09353a584000edaaa61558b27253bdea7452sewardj            specifies an address. */
470189cd09353a584000edaaa61558b27253bdea7452sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
470289cd09353a584000edaaa61558b27253bdea7452sewardj         delta += len;
470389cd09353a584000edaaa61558b27253bdea7452sewardj
470489cd09353a584000edaaa61558b27253bdea7452sewardj         switch (gregOfRM(modrm)) {
470589cd09353a584000edaaa61558b27253bdea7452sewardj
470689cd09353a584000edaaa61558b27253bdea7452sewardj            case 0: /* FILD m32int */
470789cd09353a584000edaaa61558b27253bdea7452sewardj               DIP("fildl %s\n", dis_buf);
470889cd09353a584000edaaa61558b27253bdea7452sewardj               fp_push();
47096c299f3acab617581ea504e45fbb6cab24c2b29fsewardj               put_ST(0, unop(Iop_I32StoF64,
471089cd09353a584000edaaa61558b27253bdea7452sewardj                              loadLE(Ity_I32, mkexpr(addr))));
471189cd09353a584000edaaa61558b27253bdea7452sewardj               break;
471289cd09353a584000edaaa61558b27253bdea7452sewardj
4713dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj            case 1: /* FISTTPL m32 (SSE3) */
4714dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               DIP("fisttpl %s\n", dis_buf);
4715dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               storeLE( mkexpr(addr),
47166c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) );
4717dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               fp_pop();
4718dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               break;
4719dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
47208f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj            case 2: /* FIST m32 */
472133dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fistl %s\n", dis_buf);
47228f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj               storeLE( mkexpr(addr),
47236c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
47248f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj               break;
47258f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj
472689cd09353a584000edaaa61558b27253bdea7452sewardj            case 3: /* FISTP m32 */
472733dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fistpl %s\n", dis_buf);
47288f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj               storeLE( mkexpr(addr),
47296c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
47305bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fp_pop();
473189cd09353a584000edaaa61558b27253bdea7452sewardj               break;
473217442fe8094d0f82266e5a05509f62cac8f7539esewardj
4733b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj            case 5: { /* FLD extended-real */
47347cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj               /* Uses dirty helper:
47355657923025edcb17ad6b130c3145aadabca75455sewardj                     ULong x86g_loadF80le ( UInt )
47367cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj                  addr holds the address.  First, do a dirty call to
4737b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj                  get hold of the data. */
4738c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj               IRTemp   val  = newTemp(Ity_I64);
4739c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj               IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4740c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj
47418ea867b06de73d909c29e243407713c291c8414esewardj               IRDirty* d = unsafeIRDirty_1_N (
47428ea867b06de73d909c29e243407713c291c8414esewardj                               val,
47432a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                               0/*regparms*/,
47448f40b07a47bd0fb7c6ea22dcd0e161a3ccda82ecsewardj                               "x86g_dirtyhelper_loadF80le",
47458f40b07a47bd0fb7c6ea22dcd0e161a3ccda82ecsewardj                               &x86g_dirtyhelper_loadF80le,
47468ea867b06de73d909c29e243407713c291c8414esewardj                               args
47478ea867b06de73d909c29e243407713c291c8414esewardj                            );
4748b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj               /* declare that we're reading memory */
4749b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj               d->mFx   = Ifx_Read;
475017442fe8094d0f82266e5a05509f62cac8f7539esewardj               d->mAddr = mkexpr(addr);
4751b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj               d->mSize = 10;
4752c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj
4753c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj               /* execute the dirty call, dumping the result in val. */
4754b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj               stmt( IRStmt_Dirty(d) );
4755b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj               fp_push();
4756c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj               put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4757c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj
475833dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldt %s\n", dis_buf);
475917442fe8094d0f82266e5a05509f62cac8f7539esewardj               break;
476017442fe8094d0f82266e5a05509f62cac8f7539esewardj            }
476117442fe8094d0f82266e5a05509f62cac8f7539esewardj
476217442fe8094d0f82266e5a05509f62cac8f7539esewardj            case 7: { /* FSTP extended-real */
47639fc9e782027baafd8b94163778996d6f05109f62sewardj               /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
4764c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj               IRExpr** args
4765c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj                  = mkIRExprVec_2( mkexpr(addr),
4766c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj                                   unop(Iop_ReinterpF64asI64, get_ST(0)) );
4767c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj
47688ea867b06de73d909c29e243407713c291c8414esewardj               IRDirty* d = unsafeIRDirty_0_N (
4769f96552617c82834ece36184e674e249faa899b2fsewardj                               0/*regparms*/,
47708f40b07a47bd0fb7c6ea22dcd0e161a3ccda82ecsewardj                               "x86g_dirtyhelper_storeF80le",
47718f40b07a47bd0fb7c6ea22dcd0e161a3ccda82ecsewardj                               &x86g_dirtyhelper_storeF80le,
47728ea867b06de73d909c29e243407713c291c8414esewardj                               args
47738ea867b06de73d909c29e243407713c291c8414esewardj                            );
477417442fe8094d0f82266e5a05509f62cac8f7539esewardj               /* declare we're writing memory */
477517442fe8094d0f82266e5a05509f62cac8f7539esewardj               d->mFx   = Ifx_Write;
477617442fe8094d0f82266e5a05509f62cac8f7539esewardj               d->mAddr = mkexpr(addr);
477717442fe8094d0f82266e5a05509f62cac8f7539esewardj               d->mSize = 10;
4778c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj
477917442fe8094d0f82266e5a05509f62cac8f7539esewardj               /* execute the dirty call. */
478017442fe8094d0f82266e5a05509f62cac8f7539esewardj               stmt( IRStmt_Dirty(d) );
478117442fe8094d0f82266e5a05509f62cac8f7539esewardj               fp_pop();
4782c5fc7aa465504e5d5ad2d1820a84b4c143775655sewardj
478333dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fstpt\n %s", dis_buf);
4784b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj               break;
4785b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj            }
478617442fe8094d0f82266e5a05509f62cac8f7539esewardj
4787b3bce0e2d130a9a4efcb8bcda8011fd58c4a9998sewardj            default:
478889cd09353a584000edaaa61558b27253bdea7452sewardj               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
478989cd09353a584000edaaa61558b27253bdea7452sewardj               vex_printf("first_opcode == 0xDB\n");
479089cd09353a584000edaaa61558b27253bdea7452sewardj               goto decode_fail;
479189cd09353a584000edaaa61558b27253bdea7452sewardj         }
479289cd09353a584000edaaa61558b27253bdea7452sewardj
479389cd09353a584000edaaa61558b27253bdea7452sewardj      } else {
47948308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
47958308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj         delta++;
47968308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj         switch (modrm) {
47978308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
4798519d66fc0e4f16b120079bc651862e49f154da62sewardj            case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
4799519d66fc0e4f16b120079bc651862e49f154da62sewardj               r_src = (UInt)modrm - 0xC0;
48002d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fcmovnb %%st(%d), %%st(0)\n", (Int)r_src);
4801519d66fc0e4f16b120079bc651862e49f154da62sewardj               put_ST_UNCHECKED(0,
480299dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4803009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondNB),
480499dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
4805519d66fc0e4f16b120079bc651862e49f154da62sewardj               break;
4806519d66fc0e4f16b120079bc651862e49f154da62sewardj
48074e82db7b7141106436f7f543c30050f80fcc9933sewardj            case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
48084e82db7b7141106436f7f543c30050f80fcc9933sewardj               r_src = (UInt)modrm - 0xC8;
48092d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fcmovnz %%st(%d), %%st(0)\n", (Int)r_src);
48105bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               put_ST_UNCHECKED(0,
481199dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4812009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondNZ),
481399dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
48144e82db7b7141106436f7f543c30050f80fcc9933sewardj               break;
48154e82db7b7141106436f7f543c30050f80fcc9933sewardj
4816519d66fc0e4f16b120079bc651862e49f154da62sewardj            case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
4817519d66fc0e4f16b120079bc651862e49f154da62sewardj               r_src = (UInt)modrm - 0xD0;
48182d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fcmovnbe %%st(%d), %%st(0)\n", (Int)r_src);
4819519d66fc0e4f16b120079bc651862e49f154da62sewardj               put_ST_UNCHECKED(0,
482099dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4821009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondNBE),
482299dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
4823519d66fc0e4f16b120079bc651862e49f154da62sewardj               break;
4824519d66fc0e4f16b120079bc651862e49f154da62sewardj
48258253ad3c3696f46b30daf66003f7649abe70286dsewardj            case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
48268253ad3c3696f46b30daf66003f7649abe70286dsewardj               r_src = (UInt)modrm - 0xD8;
48278253ad3c3696f46b30daf66003f7649abe70286dsewardj               DIP("fcmovnu %%st(%d), %%st(0)\n", (Int)r_src);
48288253ad3c3696f46b30daf66003f7649abe70286dsewardj               put_ST_UNCHECKED(0,
482999dd03e04a6914d90d5fee727d61d76905334becflorian                                IRExpr_ITE(
4830009230b9758291b594e60d7c0243a73d53e81854sewardj                                    mk_x86g_calculate_condition(X86CondNP),
483199dd03e04a6914d90d5fee727d61d76905334becflorian                                    get_ST(r_src), get_ST(0)) );
48328253ad3c3696f46b30daf66003f7649abe70286dsewardj               break;
48338253ad3c3696f46b30daf66003f7649abe70286dsewardj
48347df596b1e36840e2d74c90aa55589934add61ccfsewardj            case 0xE2:
48357df596b1e36840e2d74c90aa55589934add61ccfsewardj               DIP("fnclex\n");
48367df596b1e36840e2d74c90aa55589934add61ccfsewardj               break;
48377df596b1e36840e2d74c90aa55589934add61ccfsewardj
4838a0e83b06f304527e3e9aec527c344e35e7023d76sewardj            case 0xE3: {
4839a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               /* Uses dirty helper:
4840a0e83b06f304527e3e9aec527c344e35e7023d76sewardj                     void x86g_do_FINIT ( VexGuestX86State* ) */
4841a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               IRDirty* d  = unsafeIRDirty_0_N (
4842a0e83b06f304527e3e9aec527c344e35e7023d76sewardj                                0/*regparms*/,
4843a0e83b06f304527e3e9aec527c344e35e7023d76sewardj                                "x86g_dirtyhelper_FINIT",
4844a0e83b06f304527e3e9aec527c344e35e7023d76sewardj                                &x86g_dirtyhelper_FINIT,
48459041956f39c57e265122ed0a71061dea1e554edcflorian                                mkIRExprVec_1(IRExpr_BBPTR())
4846a0e83b06f304527e3e9aec527c344e35e7023d76sewardj                             );
4847a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4848a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               /* declare we're writing guest state */
4849a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->nFxState = 5;
4850c9069f2908814843e9a4da00da9c8905440195a6sewardj               vex_bzero(&d->fxState, sizeof(d->fxState));
4851a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4852a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[0].fx     = Ifx_Write;
4853a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[0].offset = OFFB_FTOP;
4854a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[0].size   = sizeof(UInt);
4855a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4856a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[1].fx     = Ifx_Write;
4857a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[1].offset = OFFB_FPREGS;
4858a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[1].size   = 8 * sizeof(ULong);
4859a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4860a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[2].fx     = Ifx_Write;
4861a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[2].offset = OFFB_FPTAGS;
4862a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[2].size   = 8 * sizeof(UChar);
4863a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4864a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[3].fx     = Ifx_Write;
4865a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[3].offset = OFFB_FPROUND;
4866a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[3].size   = sizeof(UInt);
4867a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4868a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[4].fx     = Ifx_Write;
4869a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[4].offset = OFFB_FC3210;
4870a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               d->fxState[4].size   = sizeof(UInt);
4871a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
4872a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               stmt( IRStmt_Dirty(d) );
4873a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
487433dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fninit\n");
4875a0e83b06f304527e3e9aec527c344e35e7023d76sewardj               break;
4876a0e83b06f304527e3e9aec527c344e35e7023d76sewardj            }
4877a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
48788308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
48798308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
48808308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               break;
48818308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj
488237158719b222a3776df257a80c8ce44d810fae82sewardj            case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
488337158719b222a3776df257a80c8ce44d810fae82sewardj               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
488437158719b222a3776df257a80c8ce44d810fae82sewardj               break;
488537158719b222a3776df257a80c8ce44d810fae82sewardj
48868308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj            default:
48878308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               goto decode_fail;
488817442fe8094d0f82266e5a05509f62cac8f7539esewardj         }
488989cd09353a584000edaaa61558b27253bdea7452sewardj      }
4890d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
4891d1725d18b61bf7912a9099686179faef5815dba1sewardj
4892d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4893d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
4894d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xDC) {
4895a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj      if (modrm < 0xC0) {
4896a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
489789cd09353a584000edaaa61558b27253bdea7452sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
4898feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            specifies an address. */
4899a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4900a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj         delta += len;
4901a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
4902a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj         switch (gregOfRM(modrm)) {
4903a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
4904a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj            case 0: /* FADD double-real */
4905a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4906a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               break;
4907a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
4908cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 1: /* FMUL double-real */
4909cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4910cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4911cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
4912e166ed089645c00ea80f732139c22ec2e2c402f1sewardj            case 2: /* FCOM double-real */
4913e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               DIP("fcoml %s\n", dis_buf);
4914e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               /* This forces C1 to zero, which isn't right. */
4915e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               put_C3210(
4916e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   binop( Iop_And32,
4917e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          binop(Iop_Shl32,
4918e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                binop(Iop_CmpF64,
4919e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                      get_ST(0),
4920e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                      loadLE(Ity_F64,mkexpr(addr))),
4921e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                mkU8(8)),
4922e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          mkU32(0x4500)
4923e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   ));
4924e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               break;
4925e166ed089645c00ea80f732139c22ec2e2c402f1sewardj
4926883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 3: /* FCOMP double-real */
4927e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               DIP("fcompl %s\n", dis_buf);
4928883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               /* This forces C1 to zero, which isn't right. */
4929883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               put_C3210(
4930883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                   binop( Iop_And32,
4931883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                          binop(Iop_Shl32,
4932883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                                binop(Iop_CmpF64,
4933883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                                      get_ST(0),
4934883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                                      loadLE(Ity_F64,mkexpr(addr))),
4935883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                                mkU8(8)),
4936883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                          mkU32(0x4500)
4937883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                   ));
4938883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               fp_pop();
4939883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               break;
4940883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
4941cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 4: /* FSUB double-real */
4942cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4943cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4944cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
49453fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 5: /* FSUBR double-real */
49463fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
49473fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
49483fd5e570294226c643f974b438225e3f09a82f4fsewardj
4949cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 6: /* FDIV double-real */
4950cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4951cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4952cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
4953883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 7: /* FDIVR double-real */
4954883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4955883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               break;
4956883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
4957a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj            default:
4958a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4959a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               vex_printf("first_opcode == 0xDC\n");
4960a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               goto decode_fail;
4961a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj         }
4962a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj
4963a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj      } else {
4964bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
4965bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         delta++;
4966bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         switch (modrm) {
4967bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
49683fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
49693fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
49703fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
49713fd5e570294226c643f974b438225e3f09a82f4fsewardj
4972cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4973cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4974cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4975cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
497647341042b1b4140b5b4b42983df7bec015f7beecsewardj            case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
497747341042b1b4140b5b4b42983df7bec015f7beecsewardj               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
497847341042b1b4140b5b4b42983df7bec015f7beecsewardj               break;
497947341042b1b4140b5b4b42983df7bec015f7beecsewardj
4980cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4981cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4982cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
4983cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
4984a0d48d648efc6948d5319c5b22705b397ac664b6sewardj            case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4985a0d48d648efc6948d5319c5b22705b397ac664b6sewardj               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4986a0d48d648efc6948d5319c5b22705b397ac664b6sewardj               break;
4987a0d48d648efc6948d5319c5b22705b397ac664b6sewardj
4988bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4989bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4990bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
4991bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
4992bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            default:
4993bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               goto decode_fail;
49945bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         }
4995bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
4996a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj      }
4997d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
4998d1725d18b61bf7912a9099686179faef5815dba1sewardj
4999d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5000d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
5001d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xDD) {
5002d1725d18b61bf7912a9099686179faef5815dba1sewardj
5003d1725d18b61bf7912a9099686179faef5815dba1sewardj      if (modrm < 0xC0) {
5004d1725d18b61bf7912a9099686179faef5815dba1sewardj
5005feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
5006d1725d18b61bf7912a9099686179faef5815dba1sewardj            specifies an address. */
5007bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5008bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         delta += len;
5009d1725d18b61bf7912a9099686179faef5815dba1sewardj
5010d1725d18b61bf7912a9099686179faef5815dba1sewardj         switch (gregOfRM(modrm)) {
5011d1725d18b61bf7912a9099686179faef5815dba1sewardj
5012d1725d18b61bf7912a9099686179faef5815dba1sewardj            case 0: /* FLD double-real */
501333dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fldl %s\n", dis_buf);
5014207557ab2ea38239b670785c976b89d50bbb0eccsewardj               fp_push();
5015af1cecaf9c96f99381dda16f41d286fc3e4d220asewardj               put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
5016bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               break;
5017d1725d18b61bf7912a9099686179faef5815dba1sewardj
5018dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj            case 1: /* FISTTPQ m64 (SSE3) */
5019dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               DIP("fistppll %s\n", dis_buf);
5020dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               storeLE( mkexpr(addr),
50216c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI64S, mkU32(Irrm_ZERO), get_ST(0)) );
5022dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               fp_pop();
5023dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               break;
5024dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
5025d1725d18b61bf7912a9099686179faef5815dba1sewardj            case 2: /* FST double-real */
502633dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fstl %s\n", dis_buf);
50275bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               storeLE(mkexpr(addr), get_ST(0));
5028d1725d18b61bf7912a9099686179faef5815dba1sewardj               break;
502989cd09353a584000edaaa61558b27253bdea7452sewardj
5030d1725d18b61bf7912a9099686179faef5815dba1sewardj            case 3: /* FSTP double-real */
503133dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fstpl %s\n", dis_buf);
50325bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               storeLE(mkexpr(addr), get_ST(0));
50335bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               fp_pop();
5034d1725d18b61bf7912a9099686179faef5815dba1sewardj               break;
5035d1725d18b61bf7912a9099686179faef5815dba1sewardj
50369fc9e782027baafd8b94163778996d6f05109f62sewardj            case 4: { /* FRSTOR m108 */
5037893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               /* Uses dirty helper:
50386ef84bed9bb3af22060eb1759788034602bbcc88florian                     VexEmNote x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
5039893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               IRTemp   ew = newTemp(Ity_I32);
5040893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               IRDirty* d  = unsafeIRDirty_0_N (
5041893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                                0/*regparms*/,
5042893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                                "x86g_dirtyhelper_FRSTOR",
5043893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                                &x86g_dirtyhelper_FRSTOR,
50449041956f39c57e265122ed0a71061dea1e554edcflorian                                mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
5045893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                             );
504674142b8c8d5d3b3db17d744f5d5fb80f548bcf74sewardj               d->tmp   = ew;
50479fc9e782027baafd8b94163778996d6f05109f62sewardj               /* declare we're reading memory */
50489fc9e782027baafd8b94163778996d6f05109f62sewardj               d->mFx   = Ifx_Read;
50499fc9e782027baafd8b94163778996d6f05109f62sewardj               d->mAddr = mkexpr(addr);
50509fc9e782027baafd8b94163778996d6f05109f62sewardj               d->mSize = 108;
50519fc9e782027baafd8b94163778996d6f05109f62sewardj
50529fc9e782027baafd8b94163778996d6f05109f62sewardj               /* declare we're writing guest state */
5053893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               d->nFxState = 5;
5054c9069f2908814843e9a4da00da9c8905440195a6sewardj               vex_bzero(&d->fxState, sizeof(d->fxState));
50559fc9e782027baafd8b94163778996d6f05109f62sewardj
50569fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[0].fx     = Ifx_Write;
5057c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[0].offset = OFFB_FTOP;
50589fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[0].size   = sizeof(UInt);
50599fc9e782027baafd8b94163778996d6f05109f62sewardj
50609fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[1].fx     = Ifx_Write;
5061c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[1].offset = OFFB_FPREGS;
50629fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[1].size   = 8 * sizeof(ULong);
50639fc9e782027baafd8b94163778996d6f05109f62sewardj
50649fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[2].fx     = Ifx_Write;
5065c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[2].offset = OFFB_FPTAGS;
50669fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[2].size   = 8 * sizeof(UChar);
50679fc9e782027baafd8b94163778996d6f05109f62sewardj
50689fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[3].fx     = Ifx_Write;
5069c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[3].offset = OFFB_FPROUND;
50709fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[3].size   = sizeof(UInt);
50719fc9e782027baafd8b94163778996d6f05109f62sewardj
50729fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[4].fx     = Ifx_Write;
5073c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[4].offset = OFFB_FC3210;
50749fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[4].size   = sizeof(UInt);
50759fc9e782027baafd8b94163778996d6f05109f62sewardj
50769fc9e782027baafd8b94163778996d6f05109f62sewardj               stmt( IRStmt_Dirty(d) );
50779fc9e782027baafd8b94163778996d6f05109f62sewardj
5078893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               /* ew contains any emulation warning we may need to
5079893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  issue.  If needed, side-exit to the next insn,
5080893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  reporting the warning, so that Valgrind's dispatcher
5081893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  sees the warning. */
5082893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               put_emwarn( mkexpr(ew) );
5083893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               stmt(
5084893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  IRStmt_Exit(
5085893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5086893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                     Ijk_EmWarn,
5087c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
5088c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     OFFB_EIP
5089893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                  )
5090893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               );
5091893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj
509233dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("frstor %s\n", dis_buf);
50939fc9e782027baafd8b94163778996d6f05109f62sewardj               break;
50949fc9e782027baafd8b94163778996d6f05109f62sewardj            }
50959fc9e782027baafd8b94163778996d6f05109f62sewardj
50969fc9e782027baafd8b94163778996d6f05109f62sewardj            case 6: { /* FNSAVE m108 */
5097893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               /* Uses dirty helper:
5098893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj                     void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
50999fc9e782027baafd8b94163778996d6f05109f62sewardj               IRDirty* d = unsafeIRDirty_0_N (
51009fc9e782027baafd8b94163778996d6f05109f62sewardj                               0/*regparms*/,
51019fc9e782027baafd8b94163778996d6f05109f62sewardj                               "x86g_dirtyhelper_FSAVE",
51029fc9e782027baafd8b94163778996d6f05109f62sewardj                               &x86g_dirtyhelper_FSAVE,
51039041956f39c57e265122ed0a71061dea1e554edcflorian                               mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
51049fc9e782027baafd8b94163778996d6f05109f62sewardj                            );
51059fc9e782027baafd8b94163778996d6f05109f62sewardj               /* declare we're writing memory */
51069fc9e782027baafd8b94163778996d6f05109f62sewardj               d->mFx   = Ifx_Write;
51079fc9e782027baafd8b94163778996d6f05109f62sewardj               d->mAddr = mkexpr(addr);
51089fc9e782027baafd8b94163778996d6f05109f62sewardj               d->mSize = 108;
51099fc9e782027baafd8b94163778996d6f05109f62sewardj
51109fc9e782027baafd8b94163778996d6f05109f62sewardj               /* declare we're reading guest state */
5111893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj               d->nFxState = 5;
5112c9069f2908814843e9a4da00da9c8905440195a6sewardj               vex_bzero(&d->fxState, sizeof(d->fxState));
51139fc9e782027baafd8b94163778996d6f05109f62sewardj
51149fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[0].fx     = Ifx_Read;
5115c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[0].offset = OFFB_FTOP;
51169fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[0].size   = sizeof(UInt);
51179fc9e782027baafd8b94163778996d6f05109f62sewardj
51189fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[1].fx     = Ifx_Read;
5119c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[1].offset = OFFB_FPREGS;
51209fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[1].size   = 8 * sizeof(ULong);
51219fc9e782027baafd8b94163778996d6f05109f62sewardj
51229fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[2].fx     = Ifx_Read;
5123c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[2].offset = OFFB_FPTAGS;
51249fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[2].size   = 8 * sizeof(UChar);
51259fc9e782027baafd8b94163778996d6f05109f62sewardj
51269fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[3].fx     = Ifx_Read;
5127c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[3].offset = OFFB_FPROUND;
51289fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[3].size   = sizeof(UInt);
51299fc9e782027baafd8b94163778996d6f05109f62sewardj
51309fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[4].fx     = Ifx_Read;
5131c9a43665879a03886b27a65b68af2a2c11b04f59sewardj               d->fxState[4].offset = OFFB_FC3210;
51329fc9e782027baafd8b94163778996d6f05109f62sewardj               d->fxState[4].size   = sizeof(UInt);
51339fc9e782027baafd8b94163778996d6f05109f62sewardj
51349fc9e782027baafd8b94163778996d6f05109f62sewardj               stmt( IRStmt_Dirty(d) );
51359fc9e782027baafd8b94163778996d6f05109f62sewardj
513633dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fnsave %s\n", dis_buf);
51379fc9e782027baafd8b94163778996d6f05109f62sewardj               break;
51389fc9e782027baafd8b94163778996d6f05109f62sewardj            }
51399fc9e782027baafd8b94163778996d6f05109f62sewardj
5140d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj            case 7: { /* FNSTSW m16 */
5141d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj               IRExpr* sw = get_FPU_sw();
5142dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj               vassert(typeOfIRExpr(irsb->tyenv, sw) == Ity_I16);
5143d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj               storeLE( mkexpr(addr), sw );
5144d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj               DIP("fnstsw %s\n", dis_buf);
5145d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj               break;
5146d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj            }
5147d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj
5148d1725d18b61bf7912a9099686179faef5815dba1sewardj            default:
5149bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5150bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj               vex_printf("first_opcode == 0xDD\n");
5151d1725d18b61bf7912a9099686179faef5815dba1sewardj               goto decode_fail;
5152bb53f8ccc58873ffe18bef04ba2a8d24fdc244b9sewardj         }
5153d1725d18b61bf7912a9099686179faef5815dba1sewardj      } else {
5154a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj         delta++;
5155a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj         switch (modrm) {
5156bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
51573ddedc40adb12bef9a56e872c9f561ae49a9109esewardj            case 0xC0 ... 0xC7: /* FFREE %st(?) */
51583ddedc40adb12bef9a56e872c9f561ae49a9109esewardj               r_dst = (UInt)modrm - 0xC0;
51594a6f3844a29aebc9774ab0d71418421c14ba9c41sewardj               DIP("ffree %%st(%d)\n", (Int)r_dst);
51603ddedc40adb12bef9a56e872c9f561ae49a9109esewardj               put_ST_TAG ( r_dst, mkU8(0) );
51613ddedc40adb12bef9a56e872c9f561ae49a9109esewardj               break;
51623ddedc40adb12bef9a56e872c9f561ae49a9109esewardj
516306c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj            case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
516406c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               r_dst = (UInt)modrm - 0xD0;
51652d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fst %%st(0),%%st(%d)\n", (Int)r_dst);
51665bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               /* P4 manual says: "If the destination operand is a
516706c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj                  non-empty register, the invalid-operation exception
516806c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj                  is not generated.  Hence put_ST_UNCHECKED. */
516906c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               put_ST_UNCHECKED(r_dst, get_ST(0));
517006c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj               break;
517106c32a0f13e91af2947dd01ebd4b81c01a64b15bsewardj
5172a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj            case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5173a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               r_dst = (UInt)modrm - 0xD8;
51742d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fstp %%st(0),%%st(%d)\n", (Int)r_dst);
51755bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj               /* P4 manual says: "If the destination operand is a
5176207557ab2ea38239b670785c976b89d50bbb0eccsewardj                  non-empty register, the invalid-operation exception
5177207557ab2ea38239b670785c976b89d50bbb0eccsewardj                  is not generated.  Hence put_ST_UNCHECKED. */
5178207557ab2ea38239b670785c976b89d50bbb0eccsewardj               put_ST_UNCHECKED(r_dst, get_ST(0));
5179207557ab2ea38239b670785c976b89d50bbb0eccsewardj               fp_pop();
5180a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               break;
5181bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5182bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5183bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               r_dst = (UInt)modrm - 0xE0;
51842d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fucom %%st(0),%%st(%d)\n", (Int)r_dst);
5185c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               /* This forces C1 to zero, which isn't right. */
5186c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               put_C3210(
5187c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                   binop( Iop_And32,
5188c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                          binop(Iop_Shl32,
5189c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5190c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                                mkU8(8)),
5191c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                          mkU32(0x4500)
5192c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                   ));
5193bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
5194bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5195bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5196bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               r_dst = (UInt)modrm - 0xE8;
51972d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj               DIP("fucomp %%st(0),%%st(%d)\n", (Int)r_dst);
5198c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               /* This forces C1 to zero, which isn't right. */
5199c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj               put_C3210(
5200c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                   binop( Iop_And32,
5201c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                          binop(Iop_Shl32,
5202c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5203c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                                mkU8(8)),
5204c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                          mkU32(0x4500)
5205c4be80c5f03eda35da5d9f2aeba90f27a2015b93sewardj                   ));
5206bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_pop();
5207bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
5208bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
52095bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            default:
5210a58ea668d4725b87a146cf43cc48b8ea6ead84casewardj               goto decode_fail;
52115bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         }
5212d1725d18b61bf7912a9099686179faef5815dba1sewardj      }
5213d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
5214d1725d18b61bf7912a9099686179faef5815dba1sewardj
5215d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5216d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
5217d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xDE) {
5218bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5219bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      if (modrm < 0xC0) {
5220feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5221feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
5222feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            specifies an address. */
5223feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         IROp   fop;
5224feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5225feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         delta += len;
5226feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5227feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         switch (gregOfRM(modrm)) {
5228feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5229feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 0: /* FIADD m16int */ /* ST(0) += m16int */
523033dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fiaddw %s\n", dis_buf);
5231feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fop = Iop_AddF64;
5232feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto do_fop_m16;
5233feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5234feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
523533dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fimulw %s\n", dis_buf);
5236feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fop = Iop_MulF64;
5237feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto do_fop_m16;
5238feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5239071895fca57b5b710485a4951fef12317e337064sewardj            case 2: /* FICOM m16int */
5240071895fca57b5b710485a4951fef12317e337064sewardj               DIP("ficomw %s\n", dis_buf);
5241071895fca57b5b710485a4951fef12317e337064sewardj               /* This forces C1 to zero, which isn't right. */
5242071895fca57b5b710485a4951fef12317e337064sewardj               put_C3210(
5243071895fca57b5b710485a4951fef12317e337064sewardj                   binop( Iop_And32,
5244071895fca57b5b710485a4951fef12317e337064sewardj                          binop(Iop_Shl32,
5245071895fca57b5b710485a4951fef12317e337064sewardj                                binop(Iop_CmpF64,
5246071895fca57b5b710485a4951fef12317e337064sewardj                                      get_ST(0),
52476c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                                      unop(Iop_I32StoF64,
5248071895fca57b5b710485a4951fef12317e337064sewardj                                         unop(Iop_16Sto32,
5249071895fca57b5b710485a4951fef12317e337064sewardj                                           loadLE(Ity_I16,mkexpr(addr))))),
5250071895fca57b5b710485a4951fef12317e337064sewardj                                mkU8(8)),
5251071895fca57b5b710485a4951fef12317e337064sewardj                          mkU32(0x4500)
5252071895fca57b5b710485a4951fef12317e337064sewardj                   ));
5253071895fca57b5b710485a4951fef12317e337064sewardj               break;
5254071895fca57b5b710485a4951fef12317e337064sewardj
5255071895fca57b5b710485a4951fef12317e337064sewardj            case 3: /* FICOMP m16int */
5256071895fca57b5b710485a4951fef12317e337064sewardj               DIP("ficompw %s\n", dis_buf);
5257071895fca57b5b710485a4951fef12317e337064sewardj               /* This forces C1 to zero, which isn't right. */
5258071895fca57b5b710485a4951fef12317e337064sewardj               put_C3210(
5259071895fca57b5b710485a4951fef12317e337064sewardj                   binop( Iop_And32,
5260071895fca57b5b710485a4951fef12317e337064sewardj                          binop(Iop_Shl32,
5261071895fca57b5b710485a4951fef12317e337064sewardj                                binop(Iop_CmpF64,
5262071895fca57b5b710485a4951fef12317e337064sewardj                                      get_ST(0),
52636c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                                      unop(Iop_I32StoF64,
5264071895fca57b5b710485a4951fef12317e337064sewardj                                         unop(Iop_16Sto32,
5265f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                                              loadLE(Ity_I16,mkexpr(addr))))),
5266071895fca57b5b710485a4951fef12317e337064sewardj                                mkU8(8)),
5267071895fca57b5b710485a4951fef12317e337064sewardj                          mkU32(0x4500)
5268071895fca57b5b710485a4951fef12317e337064sewardj                   ));
5269071895fca57b5b710485a4951fef12317e337064sewardj               fp_pop();
5270071895fca57b5b710485a4951fef12317e337064sewardj               break;
5271071895fca57b5b710485a4951fef12317e337064sewardj
5272feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 4: /* FISUB m16int */ /* ST(0) -= m16int */
527333dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fisubw %s\n", dis_buf);
5274feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fop = Iop_SubF64;
5275feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto do_fop_m16;
5276feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5277feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
527833dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fisubrw %s\n", dis_buf);
5279feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fop = Iop_SubF64;
5280feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto do_foprev_m16;
5281feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5282feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
528333dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fisubw %s\n", dis_buf);
5284feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fop = Iop_DivF64;
5285feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto do_fop_m16;
5286feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5287feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
528833dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fidivrw %s\n", dis_buf);
5289feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fop = Iop_DivF64;
5290feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto do_foprev_m16;
5291feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5292feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            do_fop_m16:
5293feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               put_ST_UNCHECKED(0,
5294f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(fop,
5295f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5296feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj                        get_ST(0),
52976c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        unop(Iop_I32StoF64,
5298feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj                             unop(Iop_16Sto32,
5299feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj                                  loadLE(Ity_I16, mkexpr(addr))))));
5300feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               break;
5301feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5302feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            do_foprev_m16:
5303feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               put_ST_UNCHECKED(0,
5304f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                  triop(fop,
5305f1b5b1a3c39f248c6634c78619971ac41d0a9726sewardj                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
53066c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        unop(Iop_I32StoF64,
5307feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj                             unop(Iop_16Sto32,
5308feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj                                  loadLE(Ity_I16, mkexpr(addr)))),
5309feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj                        get_ST(0)));
5310feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               break;
5311feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5312feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            default:
5313feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5314feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               vex_printf("first_opcode == 0xDE\n");
5315feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               goto decode_fail;
5316feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         }
5317bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5318bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      } else {
5319bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5320bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         delta++;
53215bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         switch (modrm) {
5322bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5323cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5324cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5325cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
5326cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
5327bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5328bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5329bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
5330bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5331e166ed089645c00ea80f732139c22ec2e2c402f1sewardj            case 0xD9: /* FCOMPP %st(0),%st(1) */
5332e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               DIP("fuompp %%st(0),%%st(1)\n");
5333e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               /* This forces C1 to zero, which isn't right. */
5334e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               put_C3210(
5335e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   binop( Iop_And32,
5336e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          binop(Iop_Shl32,
5337e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5338e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                                mkU8(8)),
5339e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                          mkU32(0x4500)
5340e166ed089645c00ea80f732139c22ec2e2c402f1sewardj                   ));
5341e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               fp_pop();
5342e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               fp_pop();
5343e166ed089645c00ea80f732139c22ec2e2c402f1sewardj               break;
5344e166ed089645c00ea80f732139c22ec2e2c402f1sewardj
5345cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5346cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0,  modrm - 0xE0, True );
5347cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
5348cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
53493fd5e570294226c643f974b438225e3f09a82f4fsewardj            case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
53503fd5e570294226c643f974b438225e3f09a82f4fsewardj               fp_do_op_ST_ST ( "sub", Iop_SubF64, 0,  modrm - 0xE8, True );
53513fd5e570294226c643f974b438225e3f09a82f4fsewardj               break;
53523fd5e570294226c643f974b438225e3f09a82f4fsewardj
5353bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5354bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5355bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
5356bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5357bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5358bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5359bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
5360bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5361bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            default:
5362bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               goto decode_fail;
53635bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         }
5364bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5365bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      }
5366d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
5367d1725d18b61bf7912a9099686179faef5815dba1sewardj
5368d1725d18b61bf7912a9099686179faef5815dba1sewardj   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5369d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
5370d1725d18b61bf7912a9099686179faef5815dba1sewardj   if (first_opcode == 0xDF) {
537189cd09353a584000edaaa61558b27253bdea7452sewardj
537289cd09353a584000edaaa61558b27253bdea7452sewardj      if (modrm < 0xC0) {
537389cd09353a584000edaaa61558b27253bdea7452sewardj
5374feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj         /* bits 5,4,3 are an opcode extension, and the modRM also
537589cd09353a584000edaaa61558b27253bdea7452sewardj            specifies an address. */
537689cd09353a584000edaaa61558b27253bdea7452sewardj         IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
537789cd09353a584000edaaa61558b27253bdea7452sewardj         delta += len;
537889cd09353a584000edaaa61558b27253bdea7452sewardj
537989cd09353a584000edaaa61558b27253bdea7452sewardj         switch (gregOfRM(modrm)) {
538089cd09353a584000edaaa61558b27253bdea7452sewardj
5381883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 0: /* FILD m16int */
5382883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               DIP("fildw %s\n", dis_buf);
5383883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               fp_push();
53846c299f3acab617581ea504e45fbb6cab24c2b29fsewardj               put_ST(0, unop(Iop_I32StoF64,
5385883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                              unop(Iop_16Sto32,
5386883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj                                   loadLE(Ity_I16, mkexpr(addr)))));
5387883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               break;
5388883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
5389dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj            case 1: /* FISTTPS m16 (SSE3) */
5390dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               DIP("fisttps %s\n", dis_buf);
5391dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               storeLE( mkexpr(addr),
53926c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI16S, mkU32(Irrm_ZERO), get_ST(0)) );
5393dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               fp_pop();
5394dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj               break;
5395dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
539637158719b222a3776df257a80c8ce44d810fae82sewardj            case 2: /* FIST m16 */
539733dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fistp %s\n", dis_buf);
539837158719b222a3776df257a80c8ce44d810fae82sewardj               storeLE( mkexpr(addr),
53996c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
540037158719b222a3776df257a80c8ce44d810fae82sewardj               break;
540137158719b222a3776df257a80c8ce44d810fae82sewardj
540289cd09353a584000edaaa61558b27253bdea7452sewardj            case 3: /* FISTP m16 */
540333dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fistps %s\n", dis_buf);
54048f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj               storeLE( mkexpr(addr),
54056c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
54068f3debf52b76a050bc84997a0358c4aa86dfc88dsewardj               fp_pop();
540789cd09353a584000edaaa61558b27253bdea7452sewardj               break;
540889cd09353a584000edaaa61558b27253bdea7452sewardj
540989cd09353a584000edaaa61558b27253bdea7452sewardj            case 5: /* FILD m64 */
541089cd09353a584000edaaa61558b27253bdea7452sewardj               DIP("fildll %s\n", dis_buf);
541189cd09353a584000edaaa61558b27253bdea7452sewardj               fp_push();
54126c299f3acab617581ea504e45fbb6cab24c2b29fsewardj               put_ST(0, binop(Iop_I64StoF64,
54134cb918d355cef4e7640d374346852db4556f3524sewardj                               get_roundingmode(),
54144cb918d355cef4e7640d374346852db4556f3524sewardj                               loadLE(Ity_I64, mkexpr(addr))));
541589cd09353a584000edaaa61558b27253bdea7452sewardj               break;
541689cd09353a584000edaaa61558b27253bdea7452sewardj
5417cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj            case 7: /* FISTP m64 */
541833dd31b1bcc175495b96222fa278062fd6116899sewardj               DIP("fistpll %s\n", dis_buf);
5419cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               storeLE( mkexpr(addr),
54206c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                        binop(Iop_F64toI64S, get_roundingmode(), get_ST(0)) );
5421cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               fp_pop();
5422cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj               break;
5423cfded9ab7c059881ecdbe967ddfcc1ce207986casewardj
542489cd09353a584000edaaa61558b27253bdea7452sewardj            default:
542589cd09353a584000edaaa61558b27253bdea7452sewardj               vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
542689cd09353a584000edaaa61558b27253bdea7452sewardj               vex_printf("first_opcode == 0xDF\n");
542789cd09353a584000edaaa61558b27253bdea7452sewardj               goto decode_fail;
542889cd09353a584000edaaa61558b27253bdea7452sewardj         }
542989cd09353a584000edaaa61558b27253bdea7452sewardj
543089cd09353a584000edaaa61558b27253bdea7452sewardj      } else {
5431bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5432bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         delta++;
54335bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         switch (modrm) {
5434bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
54358fb88693f03ab70a8122094933fe7fa3ae907bfbsewardj            case 0xC0: /* FFREEP %st(0) */
54368fb88693f03ab70a8122094933fe7fa3ae907bfbsewardj               DIP("ffreep %%st(%d)\n", 0);
54378fb88693f03ab70a8122094933fe7fa3ae907bfbsewardj               put_ST_TAG ( 0, mkU8(0) );
54388fb88693f03ab70a8122094933fe7fa3ae907bfbsewardj               fp_pop();
54398fb88693f03ab70a8122094933fe7fa3ae907bfbsewardj               break;
54408fb88693f03ab70a8122094933fe7fa3ae907bfbsewardj
5441bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            case 0xE0: /* FNSTSW %ax */
5442bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               DIP("fnstsw %%ax\n");
5443d24931d2bdee72f7c4d8def6cb21d3d6bc45022dsewardj               /* Get the FPU status word value and dump it in %AX. */
54441d2e77f4c2a59424eedbb257040d399022bab7a8sewardj               if (0) {
54451d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  /* The obvious thing to do is simply dump the 16-bit
54461d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     status word value in %AX.  However, due to a
54471d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     limitation in Memcheck's origin tracking
54481d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     machinery, this causes Memcheck not to track the
54491d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     origin of any undefinedness into %AH (only into
54501d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     %AL/%AX/%EAX), which means origins are lost in
54511d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     the sequence "fnstsw %ax; test $M,%ah; jcond .." */
54521d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  putIReg(2, R_EAX, get_FPU_sw());
54531d2e77f4c2a59424eedbb257040d399022bab7a8sewardj               } else {
54541d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  /* So a somewhat lame kludge is to make it very
54551d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     clear to Memcheck that the value is written to
54561d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     both %AH and %AL.  This generates marginally
54571d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                     worse code, but I don't think it matters much. */
54581d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  IRTemp t16 = newTemp(Ity_I16);
54591d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  assign(t16, get_FPU_sw());
54601d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  putIReg( 1, R_AL, unop(Iop_16to8, mkexpr(t16)) );
54611d2e77f4c2a59424eedbb257040d399022bab7a8sewardj                  putIReg( 1, R_AH, unop(Iop_16HIto8, mkexpr(t16)) );
54621d2e77f4c2a59424eedbb257040d399022bab7a8sewardj               }
5463bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               break;
5464bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
5465883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj            case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
54668308aad19f4ee22c7db6c23f2cb94ce8a0b77ef1sewardj               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
5467883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj               break;
5468883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
5469feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5470feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               /* not really right since COMIP != UCOMIP */
5471feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5472feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj               break;
5473feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
5474bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj            default:
5475bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               goto decode_fail;
54765bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         }
547789cd09353a584000edaaa61558b27253bdea7452sewardj      }
547889cd09353a584000edaaa61558b27253bdea7452sewardj
5479d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
5480d1725d18b61bf7912a9099686179faef5815dba1sewardj
5481d1725d18b61bf7912a9099686179faef5815dba1sewardj   else
5482d1725d18b61bf7912a9099686179faef5815dba1sewardj   vpanic("dis_FPU(x86): invalid primary opcode");
5483d1725d18b61bf7912a9099686179faef5815dba1sewardj
548469d9d664b76ef1c8a6b75917161d44c525556a19sewardj   *decode_ok = True;
548569d9d664b76ef1c8a6b75917161d44c525556a19sewardj   return delta;
548669d9d664b76ef1c8a6b75917161d44c525556a19sewardj
5487d1725d18b61bf7912a9099686179faef5815dba1sewardj  decode_fail:
5488d1725d18b61bf7912a9099686179faef5815dba1sewardj   *decode_ok = False;
5489d1725d18b61bf7912a9099686179faef5815dba1sewardj   return delta;
5490d1725d18b61bf7912a9099686179faef5815dba1sewardj}
5491d1725d18b61bf7912a9099686179faef5815dba1sewardj
5492d1725d18b61bf7912a9099686179faef5815dba1sewardj
5493464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*------------------------------------------------------------*/
5494464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*---                                                      ---*/
5495464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*--- MMX INSTRUCTIONS                                     ---*/
5496464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*---                                                      ---*/
5497464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*------------------------------------------------------------*/
5498464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5499464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/* Effect of MMX insns on x87 FPU state (table 11-2 of
5500464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   IA32 arch manual, volume 3):
5501464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5502464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   Read from, or write to MMX register (viz, any insn except EMMS):
5503464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5504464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   * FP stack pointer set to zero
5505464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5506464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   EMMS:
5507464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5508464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   * FP stack pointer set to zero
5509464efa446b2db97115d3e5f04af5db3464cc0e93sewardj*/
5510464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
55114cb918d355cef4e7640d374346852db4556f3524sewardjstatic void do_MMX_preamble ( void )
5512464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
5513dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   Int         i;
5514dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5515dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRExpr*     zero  = mkU32(0);
5516dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRExpr*     tag1  = mkU8(1);
5517464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   put_ftop(zero);
5518464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   for (i = 0; i < 8; i++)
5519d6f38b3f822f7d57adfc0da3410995d85d6a4597florian      stmt( IRStmt_PutI( mkIRPutI(descr, zero, i, tag1) ) );
5520464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
5521464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
55224cb918d355cef4e7640d374346852db4556f3524sewardjstatic void do_EMMS_preamble ( void )
5523464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
5524dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   Int         i;
5525dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5526dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRExpr*     zero  = mkU32(0);
5527dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   IRExpr*     tag0  = mkU8(0);
5528464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   put_ftop(zero);
5529464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   for (i = 0; i < 8; i++)
5530d6f38b3f822f7d57adfc0da3410995d85d6a4597florian      stmt( IRStmt_PutI( mkIRPutI(descr, zero, i, tag0) ) );
5531464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
5532464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5533464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5534464efa446b2db97115d3e5f04af5db3464cc0e93sewardjstatic IRExpr* getMMXReg ( UInt archreg )
5535464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
5536464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   vassert(archreg < 8);
5537464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5538464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
5539464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5540464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5541464efa446b2db97115d3e5f04af5db3464cc0e93sewardjstatic void putMMXReg ( UInt archreg, IRExpr* e )
5542464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
5543464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   vassert(archreg < 8);
5544dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
5545464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5546464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
5547464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5548464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
554938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj/* Helper for non-shift MMX insns.  Note this is incomplete in the
555038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   sense that it does not first call do_MMX_preamble() -- that is the
555138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   responsibility of its caller. */
555238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
5553464efa446b2db97115d3e5f04af5db3464cc0e93sewardjstatic
55542d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardjUInt dis_MMXop_regmem_to_reg ( UChar  sorb,
555552d049186d07991237a825ec88aa7f1f303edb70sewardj                               Int    delta,
55562d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj                               UChar  opc,
555755085f8680acc89d727e321f3b34cae1a8c4093aflorian                               const HChar* name,
55582d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj                               Bool   show_granularity )
5559464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
5560c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar   dis_buf[50];
556163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   UChar   modrm = getIByte(delta);
556263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   Bool    isReg = epartIsReg(modrm);
556363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   IRExpr* argL  = NULL;
556463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   IRExpr* argR  = NULL;
556538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRExpr* argG  = NULL;
556638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRExpr* argE  = NULL;
556763ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   IRTemp  res   = newTemp(Ity_I64);
5568464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
556938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   Bool    invG  = False;
557038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IROp    op    = Iop_INVALID;
557138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   void*   hAddr = NULL;
557238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   Bool    eLeft = False;
557355085f8680acc89d727e321f3b34cae1a8c4093aflorian   const HChar*  hName = NULL;
557438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
55752b7a9208ee96939f12896085a143891160dc539asewardj#  define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
5576464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5577464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   switch (opc) {
5578b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      /* Original MMX ones */
557938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xFC: op = Iop_Add8x8; break;
558038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xFD: op = Iop_Add16x4; break;
558138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xFE: op = Iop_Add32x2; break;
5582464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
558338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xEC: op = Iop_QAdd8Sx8; break;
558438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xED: op = Iop_QAdd16Sx4; break;
5585464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
558638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xDC: op = Iop_QAdd8Ux8; break;
558738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xDD: op = Iop_QAdd16Ux4; break;
5588464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
558938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF8: op = Iop_Sub8x8;  break;
559038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF9: op = Iop_Sub16x4; break;
559138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xFA: op = Iop_Sub32x2; break;
55924340dac5c2cede4962868e6da5b73282da2bc465sewardj
559338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE8: op = Iop_QSub8Sx8; break;
559438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE9: op = Iop_QSub16Sx4; break;
55954340dac5c2cede4962868e6da5b73282da2bc465sewardj
559638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD8: op = Iop_QSub8Ux8; break;
559738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD9: op = Iop_QSub16Ux4; break;
559863ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
559938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE5: op = Iop_MulHi16Sx4; break;
560038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD5: op = Iop_Mul16x4; break;
560138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
560263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
560338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x74: op = Iop_CmpEQ8x8; break;
560438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x75: op = Iop_CmpEQ16x4; break;
560538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x76: op = Iop_CmpEQ32x2; break;
560663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
560738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x64: op = Iop_CmpGT8Sx8; break;
560838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x65: op = Iop_CmpGT16Sx4; break;
560938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x66: op = Iop_CmpGT32Sx2; break;
561063ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
56115f438dd73072211989c6d496845bdc9b777ecbecsewardj      case 0x6B: op = Iop_QNarrowBin32Sto16Sx4; eLeft = True; break;
56125f438dd73072211989c6d496845bdc9b777ecbecsewardj      case 0x63: op = Iop_QNarrowBin16Sto8Sx8;  eLeft = True; break;
56135f438dd73072211989c6d496845bdc9b777ecbecsewardj      case 0x67: op = Iop_QNarrowBin16Sto8Ux8;  eLeft = True; break;
56148d14a59858e2464baa217f19daff83562f3cdca0sewardj
561538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x68: op = Iop_InterleaveHI8x8;  eLeft = True; break;
561638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
561738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
56188d14a59858e2464baa217f19daff83562f3cdca0sewardj
561938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x60: op = Iop_InterleaveLO8x8;  eLeft = True; break;
562038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
562138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
56228d14a59858e2464baa217f19daff83562f3cdca0sewardj
562338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xDB: op = Iop_And64; break;
562438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xDF: op = Iop_And64; invG = True; break;
562538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xEB: op = Iop_Or64; break;
562638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xEF: /* Possibly do better here if argL and argR are the
562738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                    same reg */
562838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 op = Iop_Xor64; break;
5629464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5630b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      /* Introduced in SSE1 */
563138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE0: op = Iop_Avg8Ux8;    break;
563238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE3: op = Iop_Avg16Ux4;   break;
563338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xEE: op = Iop_Max16Sx4;   break;
563438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xDE: op = Iop_Max8Ux8;    break;
563538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xEA: op = Iop_Min16Sx4;   break;
563638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xDA: op = Iop_Min8Ux8;    break;
563738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE4: op = Iop_MulHi16Ux4; break;
563838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
5639b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
5640164f9275c465cd09ecd09276b8542282f5def250sewardj      /* Introduced in SSE2 */
564138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD4: op = Iop_Add64; break;
564238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xFB: op = Iop_Sub64; break;
5643164f9275c465cd09ecd09276b8542282f5def250sewardj
5644464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      default:
5645464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         vex_printf("\n0x%x\n", (Int)opc);
5646464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         vpanic("dis_MMXop_regmem_to_reg");
5647464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   }
5648464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5649464efa446b2db97115d3e5f04af5db3464cc0e93sewardj#  undef XXX
5650464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
565138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   argG = getMMXReg(gregOfRM(modrm));
565238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (invG)
565338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argG = unop(Iop_Not64, argG);
565463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
5655464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   if (isReg) {
5656464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      delta++;
565738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argE = getMMXReg(eregOfRM(modrm));
5658464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   } else {
5659464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      Int    len;
5660464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5661464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      delta += len;
566238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argE = loadLE(Ity_I64, mkexpr(addr));
566363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   }
566463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
566538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (eLeft) {
566638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argL = argE;
566738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argR = argG;
566838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else {
566938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argL = argG;
567038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      argR = argE;
567138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   }
567238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
567338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (op != Iop_INVALID) {
567438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      vassert(hName == NULL);
567538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      vassert(hAddr == NULL);
567638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      assign(res, binop(op, argL, argR));
567738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else {
567838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      vassert(hName != NULL);
567938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      vassert(hAddr != NULL);
568038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      assign( res,
568138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj              mkIRExprCCall(
568238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 Ity_I64,
568338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 0/*regparms*/, hName, hAddr,
568438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 mkIRExprVec_2( argL, argR )
568538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj              )
568638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj            );
5687464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   }
5688464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
568963ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj   putMMXReg( gregOfRM(modrm), mkexpr(res) );
569063ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
5691464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   DIP("%s%s %s, %s\n",
56922d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj       name, show_granularity ? nameMMXGran(opc & 3) : "",
5693464efa446b2db97115d3e5f04af5db3464cc0e93sewardj       ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5694464efa446b2db97115d3e5f04af5db3464cc0e93sewardj       nameMMXReg(gregOfRM(modrm)) );
5695464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5696464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   return delta;
5697464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
5698464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5699464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
570038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj/* Vector by scalar shift of G by the amount specified at the bottom
570138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   of E.  This is a straight copy of dis_SSE_shiftG_byE. */
570238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
570352d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt dis_MMX_shiftG_byE ( UChar sorb, Int delta,
570455085f8680acc89d727e321f3b34cae1a8c4093aflorian                                 const HChar* opname, IROp op )
570538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj{
570638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   HChar   dis_buf[50];
570738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   Int     alen, size;
570838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  addr;
570938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   Bool    shl, shr, sar;
571038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   UChar   rm   = getIByte(delta);
571138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  g0   = newTemp(Ity_I64);
571238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  g1   = newTemp(Ity_I64);
571338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  amt  = newTemp(Ity_I32);
571438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  amt8 = newTemp(Ity_I8);
571538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
571638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (epartIsReg(rm)) {
571738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
571838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      DIP("%s %s,%s\n", opname,
571938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                        nameMMXReg(eregOfRM(rm)),
572038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                        nameMMXReg(gregOfRM(rm)) );
572138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta++;
572238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else {
572338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
572438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
572538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      DIP("%s %s,%s\n", opname,
572638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                        dis_buf,
572738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                        nameMMXReg(gregOfRM(rm)) );
572838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta += alen;
572938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   }
573038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   assign( g0,   getMMXReg(gregOfRM(rm)) );
573138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
573238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
573338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   shl = shr = sar = False;
573438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   size = 0;
573538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   switch (op) {
573638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShlN16x4: shl = True; size = 32; break;
573738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShlN32x2: shl = True; size = 32; break;
573838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_Shl64:    shl = True; size = 64; break;
573938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShrN16x4: shr = True; size = 16; break;
574038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShrN32x2: shr = True; size = 32; break;
574138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_Shr64:    shr = True; size = 64; break;
574238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_SarN16x4: sar = True; size = 16; break;
574338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_SarN32x2: sar = True; size = 32; break;
574438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      default: vassert(0);
574538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   }
574638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
574738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (shl || shr) {
574838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj     assign(
574938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj        g1,
575099dd03e04a6914d90d5fee727d61d76905334becflorian        IRExpr_ITE(
5751009230b9758291b594e60d7c0243a73d53e81854sewardj           binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
575299dd03e04a6914d90d5fee727d61d76905334becflorian           binop(op, mkexpr(g0), mkexpr(amt8)),
575399dd03e04a6914d90d5fee727d61d76905334becflorian           mkU64(0)
575438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj        )
575538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj     );
575638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else
575738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (sar) {
575838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj     assign(
575938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj        g1,
576099dd03e04a6914d90d5fee727d61d76905334becflorian        IRExpr_ITE(
5761009230b9758291b594e60d7c0243a73d53e81854sewardj           binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
576299dd03e04a6914d90d5fee727d61d76905334becflorian           binop(op, mkexpr(g0), mkexpr(amt8)),
576399dd03e04a6914d90d5fee727d61d76905334becflorian           binop(op, mkexpr(g0), mkU8(size-1))
576438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj        )
576538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj     );
576638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else {
5767ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      /*NOTREACHED*/
576838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      vassert(0);
576938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   }
577038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
577138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   putMMXReg( gregOfRM(rm), mkexpr(g1) );
577238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   return delta;
577338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj}
577438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
577538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
577638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj/* Vector by scalar shift of E by an immediate byte.  This is a
577738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   straight copy of dis_SSE_shiftE_imm. */
577838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
577938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardjstatic
578055085f8680acc89d727e321f3b34cae1a8c4093aflorianUInt dis_MMX_shiftE_imm ( Int delta, const HChar* opname, IROp op )
578138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj{
578238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   Bool    shl, shr, sar;
578338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   UChar   rm   = getIByte(delta);
578438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  e0   = newTemp(Ity_I64);
578538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  e1   = newTemp(Ity_I64);
578638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   UChar   amt, size;
578738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   vassert(epartIsReg(rm));
578838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   vassert(gregOfRM(rm) == 2
578938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj           || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
57902d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj   amt = getIByte(delta+1);
579138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   delta += 2;
579238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   DIP("%s $%d,%s\n", opname,
579338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                      (Int)amt,
579438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                      nameMMXReg(eregOfRM(rm)) );
579538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
579638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   assign( e0, getMMXReg(eregOfRM(rm)) );
579738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
579838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   shl = shr = sar = False;
579938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   size = 0;
580038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   switch (op) {
580138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShlN16x4: shl = True; size = 16; break;
580238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShlN32x2: shl = True; size = 32; break;
580338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_Shl64:    shl = True; size = 64; break;
580438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_SarN16x4: sar = True; size = 16; break;
580538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_SarN32x2: sar = True; size = 32; break;
580638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShrN16x4: shr = True; size = 16; break;
580738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_ShrN32x2: shr = True; size = 32; break;
580838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case Iop_Shr64:    shr = True; size = 64; break;
580938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      default: vassert(0);
581038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   }
581138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
581238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (shl || shr) {
5813ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      assign( e1, amt >= size
5814ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     ? mkU64(0)
5815ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     : binop(op, mkexpr(e0), mkU8(amt))
5816ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      );
581738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else
581838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   if (sar) {
5819ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      assign( e1, amt >= size
5820ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     ? binop(op, mkexpr(e0), mkU8(size-1))
5821ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     : binop(op, mkexpr(e0), mkU8(amt))
5822ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      );
582338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   } else {
5824ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      /*NOTREACHED*/
582538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      vassert(0);
582638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   }
582738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
582838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   putMMXReg( eregOfRM(rm), mkexpr(e1) );
582938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   return delta;
583038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj}
583138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
583238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
583338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj/* Completely handle all MMX instructions except emms. */
5834464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5835464efa446b2db97115d3e5f04af5db3464cc0e93sewardjstatic
583652d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, Int delta )
5837464efa446b2db97115d3e5f04af5db3464cc0e93sewardj{
5838464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   Int   len;
5839464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   UChar modrm;
5840c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
5841464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   UChar opc = getIByte(delta);
5842464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   delta++;
5843464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
58444cb918d355cef4e7640d374346852db4556f3524sewardj   /* dis_MMX handles all insns except emms. */
58454cb918d355cef4e7640d374346852db4556f3524sewardj   do_MMX_preamble();
5846464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5847464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   switch (opc) {
5848464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
58492b7a9208ee96939f12896085a143891160dc539asewardj      case 0x6E:
58502b7a9208ee96939f12896085a143891160dc539asewardj         /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
58519df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
58529df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
58532b7a9208ee96939f12896085a143891160dc539asewardj         modrm = getIByte(delta);
58542b7a9208ee96939f12896085a143891160dc539asewardj         if (epartIsReg(modrm)) {
58552b7a9208ee96939f12896085a143891160dc539asewardj            delta++;
58562b7a9208ee96939f12896085a143891160dc539asewardj            putMMXReg(
58572b7a9208ee96939f12896085a143891160dc539asewardj               gregOfRM(modrm),
58582b7a9208ee96939f12896085a143891160dc539asewardj               binop( Iop_32HLto64,
58592b7a9208ee96939f12896085a143891160dc539asewardj                      mkU32(0),
58602b7a9208ee96939f12896085a143891160dc539asewardj                      getIReg(4, eregOfRM(modrm)) ) );
58612b7a9208ee96939f12896085a143891160dc539asewardj            DIP("movd %s, %s\n",
58622b7a9208ee96939f12896085a143891160dc539asewardj                nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
58632b7a9208ee96939f12896085a143891160dc539asewardj         } else {
58642b7a9208ee96939f12896085a143891160dc539asewardj            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
58652b7a9208ee96939f12896085a143891160dc539asewardj            delta += len;
58662b7a9208ee96939f12896085a143891160dc539asewardj            putMMXReg(
58672b7a9208ee96939f12896085a143891160dc539asewardj               gregOfRM(modrm),
58682b7a9208ee96939f12896085a143891160dc539asewardj               binop( Iop_32HLto64,
58692b7a9208ee96939f12896085a143891160dc539asewardj                      mkU32(0),
58702b7a9208ee96939f12896085a143891160dc539asewardj                      loadLE(Ity_I32, mkexpr(addr)) ) );
58712b7a9208ee96939f12896085a143891160dc539asewardj            DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
58722b7a9208ee96939f12896085a143891160dc539asewardj         }
58732b7a9208ee96939f12896085a143891160dc539asewardj         break;
58742b7a9208ee96939f12896085a143891160dc539asewardj
58752b7a9208ee96939f12896085a143891160dc539asewardj      case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
58769df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
58779df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
58782b7a9208ee96939f12896085a143891160dc539asewardj         modrm = getIByte(delta);
58792b7a9208ee96939f12896085a143891160dc539asewardj         if (epartIsReg(modrm)) {
58802b7a9208ee96939f12896085a143891160dc539asewardj            delta++;
58812b7a9208ee96939f12896085a143891160dc539asewardj            putIReg( 4, eregOfRM(modrm),
58822b7a9208ee96939f12896085a143891160dc539asewardj                     unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
58832b7a9208ee96939f12896085a143891160dc539asewardj            DIP("movd %s, %s\n",
58842b7a9208ee96939f12896085a143891160dc539asewardj                nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
58852b7a9208ee96939f12896085a143891160dc539asewardj         } else {
58862b7a9208ee96939f12896085a143891160dc539asewardj            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
58872b7a9208ee96939f12896085a143891160dc539asewardj            delta += len;
58882b7a9208ee96939f12896085a143891160dc539asewardj            storeLE( mkexpr(addr),
58892b7a9208ee96939f12896085a143891160dc539asewardj                     unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
58902b7a9208ee96939f12896085a143891160dc539asewardj            DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
58912b7a9208ee96939f12896085a143891160dc539asewardj         }
58922b7a9208ee96939f12896085a143891160dc539asewardj         break;
58932b7a9208ee96939f12896085a143891160dc539asewardj
5894464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0x6F:
5895464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
58969df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
58979df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5898464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         modrm = getIByte(delta);
5899464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         if (epartIsReg(modrm)) {
5900464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            delta++;
5901464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5902464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            DIP("movq %s, %s\n",
5903464efa446b2db97115d3e5f04af5db3464cc0e93sewardj                nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5904464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         } else {
5905464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5906464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            delta += len;
5907464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5908464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            DIP("movq %s, %s\n",
5909464efa446b2db97115d3e5f04af5db3464cc0e93sewardj                dis_buf, nameMMXReg(gregOfRM(modrm)));
5910464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         }
5911464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5912a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
5913464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0x7F:
5914464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
59159df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59169df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5917464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         modrm = getIByte(delta);
5918464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         if (epartIsReg(modrm)) {
59199ca2640e485edd83d16249ad29b40b081e273dedsewardj            delta++;
59209ca2640e485edd83d16249ad29b40b081e273dedsewardj            putMMXReg( eregOfRM(modrm), getMMXReg(gregOfRM(modrm)) );
59219ca2640e485edd83d16249ad29b40b081e273dedsewardj            DIP("movq %s, %s\n",
59229ca2640e485edd83d16249ad29b40b081e273dedsewardj                nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
5923464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         } else {
5924464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5925464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            delta += len;
5926893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj            storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
5927464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            DIP("mov(nt)q %s, %s\n",
5928464efa446b2db97115d3e5f04af5db3464cc0e93sewardj                nameMMXReg(gregOfRM(modrm)), dis_buf);
5929464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         }
5930464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5931464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59324340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xFC:
59334340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xFD:
59344340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
59359df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59369df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5937464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5938464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5939464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59404340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xEC:
59414340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
59429df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59439df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5944464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5945464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5946464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59474340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xDC:
59484340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
59499df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59509df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5951464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5952464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5953464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59544340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xF8:
59554340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xF9:
59564340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
59579df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59589df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5959464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
5960464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5961464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59624340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xE8:
59634340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
59649df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59659df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5966464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5967464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5968464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59694340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xD8:
59704340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
59719df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59729df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5973464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5974464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5975464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5976464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
59779df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59789df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5979464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5980464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5981464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
5982464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
59839df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59849df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
5985464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5986464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
5987464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
59884340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
59894340dac5c2cede4962868e6da5b73282da2bc465sewardj         vassert(sz == 4);
59904340dac5c2cede4962868e6da5b73282da2bc465sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
59914340dac5c2cede4962868e6da5b73282da2bc465sewardj         break;
59924340dac5c2cede4962868e6da5b73282da2bc465sewardj
59934340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x74:
59944340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x75:
59954340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
59969df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
59979df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
59984340dac5c2cede4962868e6da5b73282da2bc465sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
59994340dac5c2cede4962868e6da5b73282da2bc465sewardj         break;
60004340dac5c2cede4962868e6da5b73282da2bc465sewardj
60014340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x64:
60024340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x65:
60034340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
60049df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60059df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
60064340dac5c2cede4962868e6da5b73282da2bc465sewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
60074340dac5c2cede4962868e6da5b73282da2bc465sewardj         break;
60084340dac5c2cede4962868e6da5b73282da2bc465sewardj
600963ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
60109df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60119df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
601263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
601363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
601463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
601563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
60169df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60179df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
601863ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
601963ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
602063ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
602163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
60229df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60239df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
602463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
602563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
602663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
602763ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x68:
602863ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x69:
602963ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
60309df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60319df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
603263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
603363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
603463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
603563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x60:
603663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x61:
603763ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
60389df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60399df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
604063ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
604163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
604263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
604363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
60449df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60459df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
604663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
604763ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
604863ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
604963ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
60509df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60519df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
605263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
605363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
605463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
605563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
60569df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60579df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
605863ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
605963ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         break;
606063ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
606163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
60629df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         if (sz != 4)
60639df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj            goto mmx_decode_failure;
606463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj         delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
606538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj         break;
606663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
606738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj#     define SHIFT_BY_REG(_name,_op)                                 \
606838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
606938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                break;
60708d14a59858e2464baa217f19daff83562f3cdca0sewardj
607138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
607238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
607338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
607438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
60758d14a59858e2464baa217f19daff83562f3cdca0sewardj
607638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
607738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
607838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
607938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
608038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
608138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
608238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
608338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
608438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
608538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj#     undef SHIFT_BY_REG
60868d14a59858e2464baa217f19daff83562f3cdca0sewardj
60872b7a9208ee96939f12896085a143891160dc539asewardj      case 0x71:
60882b7a9208ee96939f12896085a143891160dc539asewardj      case 0x72:
60892b7a9208ee96939f12896085a143891160dc539asewardj      case 0x73: {
60902b7a9208ee96939f12896085a143891160dc539asewardj         /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
6091a8415ffe6c6f0e73519301a55026a4071c701fd1sewardj         UChar byte2, subopc;
609238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj         if (sz != 4)
609338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj            goto mmx_decode_failure;
609438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj         byte2  = getIByte(delta);           /* amode / sub-opcode */
60959b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj         subopc = toUChar( (byte2 >> 3) & 7 );
60962b7a9208ee96939f12896085a143891160dc539asewardj
609738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj#        define SHIFT_BY_IMM(_name,_op)                         \
609838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj             do { delta = dis_MMX_shiftE_imm(delta,_name,_op);  \
609938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj             } while (0)
61002b7a9208ee96939f12896085a143891160dc539asewardj
61012b7a9208ee96939f12896085a143891160dc539asewardj              if (subopc == 2 /*SRL*/ && opc == 0x71)
610238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
61032b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 2 /*SRL*/ && opc == 0x72)
610438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
61052b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 2 /*SRL*/ && opc == 0x73)
610638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psrlq", Iop_Shr64);
61072b7a9208ee96939f12896085a143891160dc539asewardj
61082b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 4 /*SAR*/ && opc == 0x71)
610938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
61102b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 4 /*SAR*/ && opc == 0x72)
611138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
61122b7a9208ee96939f12896085a143891160dc539asewardj
61132b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 6 /*SHL*/ && opc == 0x71)
611438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
61152b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 6 /*SHL*/ && opc == 0x72)
611638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
61172b7a9208ee96939f12896085a143891160dc539asewardj         else if (subopc == 6 /*SHL*/ && opc == 0x73)
611838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj                 SHIFT_BY_IMM("psllq", Iop_Shl64);
61192b7a9208ee96939f12896085a143891160dc539asewardj
61202b7a9208ee96939f12896085a143891160dc539asewardj         else goto mmx_decode_failure;
61212b7a9208ee96939f12896085a143891160dc539asewardj
612238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj#        undef SHIFT_BY_IMM
61232b7a9208ee96939f12896085a143891160dc539asewardj         break;
61242b7a9208ee96939f12896085a143891160dc539asewardj      }
61252b7a9208ee96939f12896085a143891160dc539asewardj
6126d71ba837242cc470f622335b1c650bce8886a533sewardj      case 0xF7: {
6127d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp addr    = newTemp(Ity_I32);
6128d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp regD    = newTemp(Ity_I64);
6129d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp regM    = newTemp(Ity_I64);
6130d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp mask    = newTemp(Ity_I64);
6131d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp olddata = newTemp(Ity_I64);
6132d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp newdata = newTemp(Ity_I64);
6133d71ba837242cc470f622335b1c650bce8886a533sewardj
6134d71ba837242cc470f622335b1c650bce8886a533sewardj         modrm = getIByte(delta);
6135d71ba837242cc470f622335b1c650bce8886a533sewardj         if (sz != 4 || (!epartIsReg(modrm)))
6136d71ba837242cc470f622335b1c650bce8886a533sewardj            goto mmx_decode_failure;
6137d71ba837242cc470f622335b1c650bce8886a533sewardj         delta++;
6138d71ba837242cc470f622335b1c650bce8886a533sewardj
6139d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
6140d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( regM, getMMXReg( eregOfRM(modrm) ));
6141d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( regD, getMMXReg( gregOfRM(modrm) ));
6142d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( mask, binop(Iop_SarN8x8, mkexpr(regM), mkU8(7)) );
6143d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( olddata, loadLE( Ity_I64, mkexpr(addr) ));
6144d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( newdata,
6145d71ba837242cc470f622335b1c650bce8886a533sewardj                 binop(Iop_Or64,
6146d71ba837242cc470f622335b1c650bce8886a533sewardj                       binop(Iop_And64,
6147d71ba837242cc470f622335b1c650bce8886a533sewardj                             mkexpr(regD),
6148d71ba837242cc470f622335b1c650bce8886a533sewardj                             mkexpr(mask) ),
6149d71ba837242cc470f622335b1c650bce8886a533sewardj                       binop(Iop_And64,
6150d71ba837242cc470f622335b1c650bce8886a533sewardj                             mkexpr(olddata),
6151d71ba837242cc470f622335b1c650bce8886a533sewardj                             unop(Iop_Not64, mkexpr(mask)))) );
6152d71ba837242cc470f622335b1c650bce8886a533sewardj         storeLE( mkexpr(addr), mkexpr(newdata) );
6153d71ba837242cc470f622335b1c650bce8886a533sewardj         DIP("maskmovq %s,%s\n", nameMMXReg( eregOfRM(modrm) ),
6154d71ba837242cc470f622335b1c650bce8886a533sewardj                                 nameMMXReg( gregOfRM(modrm) ) );
6155d71ba837242cc470f622335b1c650bce8886a533sewardj         break;
6156d71ba837242cc470f622335b1c650bce8886a533sewardj      }
6157d71ba837242cc470f622335b1c650bce8886a533sewardj
61582b7a9208ee96939f12896085a143891160dc539asewardj      /* --- MMX decode failure --- */
6159464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      default:
61602b7a9208ee96939f12896085a143891160dc539asewardj      mmx_decode_failure:
6161464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         *decode_ok = False;
6162464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         return delta; /* ignored */
6163464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
6164464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   }
6165464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
6166464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   *decode_ok = True;
6167464efa446b2db97115d3e5f04af5db3464cc0e93sewardj   return delta;
6168464efa446b2db97115d3e5f04af5db3464cc0e93sewardj}
6169464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
6170464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
6171464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*------------------------------------------------------------*/
6172464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*--- More misc arithmetic and other obscure insns.        ---*/
6173464efa446b2db97115d3e5f04af5db3464cc0e93sewardj/*------------------------------------------------------------*/
6174a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6175a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj/* Double length left and right shifts.  Apparently only required in
6176a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   v-size (no b- variant). */
6177a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardjstatic
6178a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardjUInt dis_SHLRD_Gv_Ev ( UChar sorb,
617952d049186d07991237a825ec88aa7f1f303edb70sewardj                       Int delta, UChar modrm,
6180a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                       Int sz,
6181a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                       IRExpr* shift_amt,
6182a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                       Bool amt_is_literal,
618355085f8680acc89d727e321f3b34cae1a8c4093aflorian                       const HChar* shift_amt_txt,
6184a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                       Bool left_shift )
6185a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj{
6186a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   /* shift_amt :: Ity_I8 is the amount to shift.  shift_amt_txt is used
6187a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      for printing it.   And eip on entry points at the modrm byte. */
6188a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   Int len;
6189c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
6190a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
61916d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRType ty       = szToITy(sz);
61926d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp gsrc     = newTemp(ty);
61936d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp esrc     = newTemp(ty);
619492d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp addr     = IRTemp_INVALID;
61956d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj   IRTemp tmpSH    = newTemp(Ity_I8);
619692d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp tmpL     = IRTemp_INVALID;
619792d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp tmpRes   = IRTemp_INVALID;
619892d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp tmpSubSh = IRTemp_INVALID;
6199a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   IROp   mkpair;
6200a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   IROp   getres;
6201a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   IROp   shift;
6202a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   IRExpr* mask = NULL;
6203a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6204a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   vassert(sz == 2 || sz == 4);
6205a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6206a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   /* The E-part is the destination; this is shifted.  The G-part
6207a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      supplies bits to be shifted into the E-part, but is not
6208a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      changed.
6209a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6210a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      If shifting left, form a double-length word with E at the top
6211a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      and G at the bottom, and shift this left.  The result is then in
6212a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      the high part.
6213a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6214a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      If shifting right, form a double-length word with G at the top
6215a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      and E at the bottom, and shift this right.  The result is then
6216a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      at the bottom.  */
6217a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6218a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   /* Fetch the operands. */
6219a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6220a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
6221a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6222a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   if (epartIsReg(modrm)) {
6223a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      delta++;
6224a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      assign( esrc, getIReg(sz, eregOfRM(modrm)) );
622568511549b138ef55c8d31088cb0f20a72d83ab2bsewardj      DIP("sh%cd%c %s, %s, %s\n",
6226a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj          ( left_shift ? 'l' : 'r' ), nameISize(sz),
622768511549b138ef55c8d31088cb0f20a72d83ab2bsewardj          shift_amt_txt,
6228a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj          nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
6229a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   } else {
6230a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      addr = disAMode ( &len, sorb, delta, dis_buf );
6231a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      delta += len;
6232a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      assign( esrc, loadLE(ty, mkexpr(addr)) );
623368511549b138ef55c8d31088cb0f20a72d83ab2bsewardj      DIP("sh%cd%c %s, %s, %s\n",
623468511549b138ef55c8d31088cb0f20a72d83ab2bsewardj          ( left_shift ? 'l' : 'r' ), nameISize(sz),
623568511549b138ef55c8d31088cb0f20a72d83ab2bsewardj          shift_amt_txt,
623668511549b138ef55c8d31088cb0f20a72d83ab2bsewardj          nameIReg(sz, gregOfRM(modrm)), dis_buf);
6237a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   }
6238a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6239a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   /* Round up the relevant primops. */
6240a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6241a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   if (sz == 4) {
6242a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      tmpL     = newTemp(Ity_I64);
6243a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      tmpRes   = newTemp(Ity_I32);
6244a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      tmpSubSh = newTemp(Ity_I32);
6245e539a4055b785d1ee978727e51bcc4b39f3e2c1asewardj      mkpair   = Iop_32HLto64;
62468c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      getres   = left_shift ? Iop_64HIto32 : Iop_64to32;
6247e539a4055b785d1ee978727e51bcc4b39f3e2c1asewardj      shift    = left_shift ? Iop_Shl64 : Iop_Shr64;
6248e539a4055b785d1ee978727e51bcc4b39f3e2c1asewardj      mask     = mkU8(31);
6249a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   } else {
6250a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      /* sz == 2 */
62518c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      tmpL     = newTemp(Ity_I32);
62528c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      tmpRes   = newTemp(Ity_I16);
62538c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      tmpSubSh = newTemp(Ity_I16);
62548c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      mkpair   = Iop_16HLto32;
62558c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      getres   = left_shift ? Iop_32HIto16 : Iop_32to16;
62568c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      shift    = left_shift ? Iop_Shl32 : Iop_Shr32;
62578c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      mask     = mkU8(15);
6258a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   }
6259a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6260a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   /* Do the shift, calculate the subshift value, and set
6261a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      the flag thunk. */
6262a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
62638c7f1abe9e022f6382634efea09c9cac89ec6336sewardj   assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
62648c7f1abe9e022f6382634efea09c9cac89ec6336sewardj
6265a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   if (left_shift)
6266a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
6267a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   else
6268a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
6269a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6270a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
6271a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   assign( tmpSubSh,
6272a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj           unop(getres,
6273a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                binop(shift,
6274a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                      mkexpr(tmpL),
6275a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                      binop(Iop_And8,
6276a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                            binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6277a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                            mask))) );
6278a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
62792a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
62802a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj                              tmpRes, tmpSubSh, ty, tmpSH );
6281a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6282a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   /* Put result back. */
6283a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6284a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   if (epartIsReg(modrm)) {
6285a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
6286a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   } else {
6287a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      storeLE( mkexpr(addr), mkexpr(tmpRes) );
6288a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   }
6289a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6290a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   if (amt_is_literal) delta++;
6291a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj   return delta;
6292a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj}
6293a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
6294a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
62951c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj/* Handle BT/BTS/BTR/BTC Gv, Ev.  Apparently b-size is not
62961c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   required. */
62971c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
62981c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardjtypedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
62991c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
630055085f8680acc89d727e321f3b34cae1a8c4093aflorianstatic const HChar* nameBtOp ( BtOp op )
63011c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj{
63021c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   switch (op) {
63031c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case BtOpNone:  return "";
63041c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case BtOpSet:   return "s";
63051c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case BtOpReset: return "r";
63061c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case BtOpComp:  return "c";
63071c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      default: vpanic("nameBtOp(x86)");
63081c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   }
63091c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj}
63101c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63111c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63121c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardjstatic
6313cacba8e675988fbf21b08feea1f317a9c896c053florianUInt dis_bt_G_E ( const VexAbiInfo* vbi,
63140283430ee809d645864ddd2da5f450f88142b4cdsewardj                  UChar sorb, Bool locked, Int sz, Int delta, BtOp op )
63151c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj{
6316c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar  dis_buf[50];
63171c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   UChar  modrm;
63181c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   Int    len;
63191c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
6320e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj          t_addr1, t_esp, t_mask, t_new;
63211c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63221c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   vassert(sz == 2 || sz == 4);
63231c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63241c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   t_fetched = t_bitno0 = t_bitno1 = t_bitno2
6325e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj             = t_addr0 = t_addr1 = t_esp
6326e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj             = t_mask = t_new = IRTemp_INVALID;
63271c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63281c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   t_fetched = newTemp(Ity_I8);
6329e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   t_new     = newTemp(Ity_I8);
63301c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   t_bitno0  = newTemp(Ity_I32);
63311c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   t_bitno1  = newTemp(Ity_I32);
63321c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   t_bitno2  = newTemp(Ity_I8);
63331c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   t_addr1   = newTemp(Ity_I32);
63341c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   modrm     = getIByte(delta);
63351c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63369ed1680d3094c6ecb6d9b8cbb58f7ef5d30b71b0sewardj   assign( t_bitno0, widenSto32(getIReg(sz, gregOfRM(modrm))) );
63371c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63381c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   if (epartIsReg(modrm)) {
63391c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      delta++;
63401c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      /* Get it onto the client's stack. */
63411c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      t_esp = newTemp(Ity_I32);
63421c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      t_addr0 = newTemp(Ity_I32);
63431c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63440283430ee809d645864ddd2da5f450f88142b4cdsewardj      /* For the choice of the value 128, see comment in dis_bt_G_E in
63450283430ee809d645864ddd2da5f450f88142b4cdsewardj         guest_amd64_toIR.c.  We point out here only that 128 is
63460283430ee809d645864ddd2da5f450f88142b4cdsewardj         fast-cased in Memcheck and is > 0, so seems like a good
63470283430ee809d645864ddd2da5f450f88142b4cdsewardj         choice. */
63480283430ee809d645864ddd2da5f450f88142b4cdsewardj      vassert(vbi->guest_stack_redzone_size == 0);
63490283430ee809d645864ddd2da5f450f88142b4cdsewardj      assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(128)) );
63501c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      putIReg(4, R_ESP, mkexpr(t_esp));
63511c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63521c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
63531c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63541c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      /* Make t_addr0 point at it. */
63551c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      assign( t_addr0, mkexpr(t_esp) );
63561c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63571c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      /* Mask out upper bits of the shift amount, since we're doing a
63581c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj         reg. */
63591c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      assign( t_bitno1, binop(Iop_And32,
63601c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                              mkexpr(t_bitno0),
63611c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                              mkU32(sz == 4 ? 31 : 15)) );
63621c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63631c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   } else {
63641c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
63651c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      delta += len;
63661c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      assign( t_bitno1, mkexpr(t_bitno0) );
63671c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   }
63681c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63691c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* At this point: t_addr0 is the address being operated on.  If it
63701c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      was a reg, we will have pushed it onto the client's stack.
63711c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      t_bitno1 is the bit number, suitably masked in the case of a
63721c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      reg.  */
63731c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63741c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* Now the main sequence. */
63751c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   assign( t_addr1,
63761c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj           binop(Iop_Add32,
63771c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                 mkexpr(t_addr0),
63781c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
63791c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63801c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* t_addr1 now holds effective address */
63811c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63821c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   assign( t_bitno2,
63831c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj           unop(Iop_32to8,
63841c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
63851c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63861c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* t_bitno2 contains offset of bit within byte */
63871c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63881c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   if (op != BtOpNone) {
63891c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      t_mask = newTemp(Ity_I8);
63901c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
63911c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   }
63924963a42df83976b446e204c7f1eb587021bd94a3sewardj
63931c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* t_mask is now a suitable byte mask */
63941c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63951c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
63961c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
63971c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   if (op != BtOpNone) {
63981c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      switch (op) {
6399e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         case BtOpSet:
6400e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            assign( t_new,
6401e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                    binop(Iop_Or8, mkexpr(t_fetched), mkexpr(t_mask)) );
64021c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj            break;
6403e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         case BtOpComp:
6404e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            assign( t_new,
6405e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                    binop(Iop_Xor8, mkexpr(t_fetched), mkexpr(t_mask)) );
64061c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj            break;
6407e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         case BtOpReset:
6408e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            assign( t_new,
6409e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                    binop(Iop_And8, mkexpr(t_fetched),
6410e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                    unop(Iop_Not8, mkexpr(t_mask))) );
64111c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj            break;
64121c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj         default:
64131c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj            vpanic("dis_bt_G_E(x86)");
64141c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      }
6415e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      if (locked && !epartIsReg(modrm)) {
6416e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         casLE( mkexpr(t_addr1), mkexpr(t_fetched)/*expd*/,
6417e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                 mkexpr(t_new)/*new*/,
6418e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                 guest_EIP_curr_instr );
6419e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      } else {
6420e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         storeLE( mkexpr(t_addr1), mkexpr(t_new) );
6421e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      }
64221c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   }
64231c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
64241c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* Side effect done; now get selected bit into Carry flag */
64252a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
64262a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
64272a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
64281c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   stmt( IRStmt_Put(
64292a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            OFFB_CC_DEP1,
64301c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj            binop(Iop_And32,
64311c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                  binop(Iop_Shr32,
64321c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj                        unop(Iop_8Uto32, mkexpr(t_fetched)),
64335bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                        mkexpr(t_bitno2)),
64345bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                  mkU32(1)))
64351c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj       );
6436a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
6437a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      elimination of previous stores to this field work better. */
6438a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
64391c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
64401c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* Move reg operand from stack back to reg */
64411c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   if (epartIsReg(modrm)) {
64421c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      /* t_esp still points at it. */
64434963a42df83976b446e204c7f1eb587021bd94a3sewardj      putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
64440283430ee809d645864ddd2da5f450f88142b4cdsewardj      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(128)) );
64451c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   }
64461c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
64471c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   DIP("bt%s%c %s, %s\n",
64481c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj       nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
64491c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj       ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
64501c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
64511c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   return delta;
64521c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj}
6453ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6454ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6455ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6456ce646f23d71ac432c340667387aa4a5ce7d18099sewardj/* Handle BSF/BSR.  Only v-size seems necessary. */
6457ce646f23d71ac432c340667387aa4a5ce7d18099sewardjstatic
645852d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_bs_E_G ( UChar sorb, Int sz, Int delta, Bool fwds )
6459ce646f23d71ac432c340667387aa4a5ce7d18099sewardj{
6460ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   Bool   isReg;
6461ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   UChar  modrm;
6462c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar  dis_buf[50];
6463ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6464ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   IRType ty  = szToITy(sz);
6465ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   IRTemp src = newTemp(ty);
6466ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   IRTemp dst = newTemp(ty);
6467ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6468ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   IRTemp src32 = newTemp(Ity_I32);
6469ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   IRTemp dst32 = newTemp(Ity_I32);
6470009230b9758291b594e60d7c0243a73d53e81854sewardj   IRTemp srcB  = newTemp(Ity_I1);
6471ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6472ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   vassert(sz == 4 || sz == 2);
6473ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6474ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   modrm = getIByte(delta);
6475ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6476ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   isReg = epartIsReg(modrm);
6477ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   if (isReg) {
6478ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      delta++;
6479ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      assign( src, getIReg(sz, eregOfRM(modrm)) );
6480ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   } else {
6481ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      Int    len;
6482ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6483ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      delta += len;
6484ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      assign( src, loadLE(ty, mkexpr(addr)) );
6485ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   }
6486ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6487ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   DIP("bs%c%c %s, %s\n",
6488ce646f23d71ac432c340667387aa4a5ce7d18099sewardj       fwds ? 'f' : 'r', nameISize(sz),
6489ce646f23d71ac432c340667387aa4a5ce7d18099sewardj       ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
6490ce646f23d71ac432c340667387aa4a5ce7d18099sewardj       nameIReg(sz, gregOfRM(modrm)));
6491ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6492009230b9758291b594e60d7c0243a73d53e81854sewardj   /* Generate a bool expression which is zero iff the original is
6493e13074c2c1321d069fb95806bdce64f9a3512341sewardj      zero, and nonzero otherwise.  Ask for a CmpNE version which, if
6494e13074c2c1321d069fb95806bdce64f9a3512341sewardj      instrumented by Memcheck, is instrumented expensively, since
6495e13074c2c1321d069fb95806bdce64f9a3512341sewardj      this may be used on the output of a preceding movmskb insn,
6496e13074c2c1321d069fb95806bdce64f9a3512341sewardj      which has been known to be partially defined, and in need of
6497e13074c2c1321d069fb95806bdce64f9a3512341sewardj      careful handling. */
6498009230b9758291b594e60d7c0243a73d53e81854sewardj   assign( srcB, binop(mkSizedOp(ty,Iop_ExpCmpNE8),
6499009230b9758291b594e60d7c0243a73d53e81854sewardj                       mkexpr(src), mkU(ty,0)) );
6500ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6501ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   /* Flags: Z is 1 iff source value is zero.  All others
6502ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      are undefined -- we force them to zero. */
65032a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
65042a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6505ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   stmt( IRStmt_Put(
65062a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj            OFFB_CC_DEP1,
650799dd03e04a6914d90d5fee727d61d76905334becflorian            IRExpr_ITE( mkexpr(srcB),
650899dd03e04a6914d90d5fee727d61d76905334becflorian                        /* src!=0 */
650999dd03e04a6914d90d5fee727d61d76905334becflorian                        mkU32(0),
651099dd03e04a6914d90d5fee727d61d76905334becflorian                        /* src==0 */
651199dd03e04a6914d90d5fee727d61d76905334becflorian                        mkU32(X86G_CC_MASK_Z)
6512ce646f23d71ac432c340667387aa4a5ce7d18099sewardj                        )
6513ce646f23d71ac432c340667387aa4a5ce7d18099sewardj       ));
6514a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
6515a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      elimination of previous stores to this field work better. */
6516a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
6517ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6518ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   /* Result: iff source value is zero, we can't use
6519ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
6520ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      But anyway, Intel x86 semantics say the result is undefined in
6521ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      such situations.  Hence handle the zero case specially. */
6522ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6523ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   /* Bleh.  What we compute:
6524ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6525ce646f23d71ac432c340667387aa4a5ce7d18099sewardj          bsf32:  if src == 0 then 0 else  Ctz32(src)
6526ce646f23d71ac432c340667387aa4a5ce7d18099sewardj          bsr32:  if src == 0 then 0 else  31 - Clz32(src)
6527ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6528ce646f23d71ac432c340667387aa4a5ce7d18099sewardj          bsf16:  if src == 0 then 0 else  Ctz32(16Uto32(src))
6529ce646f23d71ac432c340667387aa4a5ce7d18099sewardj          bsr16:  if src == 0 then 0 else  31 - Clz32(16Uto32(src))
6530ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6531ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      First, widen src to 32 bits if it is not already.
653237158719b222a3776df257a80c8ce44d810fae82sewardj
653337158719b222a3776df257a80c8ce44d810fae82sewardj      Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
653437158719b222a3776df257a80c8ce44d810fae82sewardj      dst register unchanged when src == 0.  Hence change accordingly.
6535ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   */
6536ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   if (sz == 2)
6537ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
6538ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   else
6539ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      assign( src32, mkexpr(src) );
6540ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6541ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   /* The main computation, guarding against zero. */
6542ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   assign( dst32,
654399dd03e04a6914d90d5fee727d61d76905334becflorian           IRExpr_ITE(
6544009230b9758291b594e60d7c0243a73d53e81854sewardj              mkexpr(srcB),
6545ce646f23d71ac432c340667387aa4a5ce7d18099sewardj              /* src != 0 */
6546ce646f23d71ac432c340667387aa4a5ce7d18099sewardj              fwds ? unop(Iop_Ctz32, mkexpr(src32))
6547ce646f23d71ac432c340667387aa4a5ce7d18099sewardj                   : binop(Iop_Sub32,
6548ce646f23d71ac432c340667387aa4a5ce7d18099sewardj                           mkU32(31),
654999dd03e04a6914d90d5fee727d61d76905334becflorian                           unop(Iop_Clz32, mkexpr(src32))),
655099dd03e04a6914d90d5fee727d61d76905334becflorian              /* src == 0 -- leave dst unchanged */
655199dd03e04a6914d90d5fee727d61d76905334becflorian              widenUto32( getIReg( sz, gregOfRM(modrm) ) )
6552ce646f23d71ac432c340667387aa4a5ce7d18099sewardj           )
6553ce646f23d71ac432c340667387aa4a5ce7d18099sewardj         );
6554ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6555ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   if (sz == 2)
6556ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
6557ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   else
6558ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      assign( dst, mkexpr(dst32) );
6559ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6560ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   /* dump result back */
6561ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
6562ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
6563ce646f23d71ac432c340667387aa4a5ce7d18099sewardj   return delta;
6564ce646f23d71ac432c340667387aa4a5ce7d18099sewardj}
656564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
656664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
656764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjstatic
656864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardjvoid codegen_xchg_eAX_Reg ( Int sz, Int reg )
656964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj{
657064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRType ty = szToITy(sz);
657164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp t1 = newTemp(ty);
657264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   IRTemp t2 = newTemp(ty);
657364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   vassert(sz == 2 || sz == 4);
657464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( t1, getIReg(sz, R_EAX) );
657564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   assign( t2, getIReg(sz, reg) );
657664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg( sz, R_EAX, mkexpr(t2) );
657764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   putIReg( sz, reg, mkexpr(t1) );
657864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   DIP("xchg%c %s, %s\n",
657964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj       nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
658064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj}
658164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
658264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
6583bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardjstatic
6584bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardjvoid codegen_SAHF ( void )
6585bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj{
6586bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   /* Set the flags to:
65872a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      (x86g_calculate_flags_all() & X86G_CC_MASK_O)  -- retain the old O flag
65882a9ad023890d3b34cf45e429df2a8ae88b419128sewardj      | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
65892a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                |X86G_CC_MASK_P|X86G_CC_MASK_C)
6590bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   */
65912a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   UInt   mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
65922a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                       |X86G_CC_MASK_C|X86G_CC_MASK_P;
6593bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   IRTemp oldflags   = newTemp(Ity_I32);
65942a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   assign( oldflags, mk_x86g_calculate_eflags_all() );
65952a9ad023890d3b34cf45e429df2a8ae88b419128sewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
6596905edbde84c49991a1f27c726eda02b338460c8esewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
65972a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
65982a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj   stmt( IRStmt_Put( OFFB_CC_DEP1,
6599bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj         binop(Iop_Or32,
66002a9ad023890d3b34cf45e429df2a8ae88b419128sewardj               binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
6601bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj               binop(Iop_And32,
6602bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj                     binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
6603bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj                     mkU32(mask_SZACP))
6604bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj              )
6605bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   ));
6606a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
6607a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      elimination of previous stores to this field work better. */
6608a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
6609bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj}
6610bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
6611bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
66128dfdc8a059e35940fe96371360cae39d9724cea9sewardjstatic
66138dfdc8a059e35940fe96371360cae39d9724cea9sewardjvoid codegen_LAHF ( void  )
66148dfdc8a059e35940fe96371360cae39d9724cea9sewardj{
66158dfdc8a059e35940fe96371360cae39d9724cea9sewardj   /* AH <- EFLAGS(SF:ZF:0:AF:0:PF:1:CF) */
66168dfdc8a059e35940fe96371360cae39d9724cea9sewardj   IRExpr* eax_with_hole;
66178dfdc8a059e35940fe96371360cae39d9724cea9sewardj   IRExpr* new_byte;
66188dfdc8a059e35940fe96371360cae39d9724cea9sewardj   IRExpr* new_eax;
66198dfdc8a059e35940fe96371360cae39d9724cea9sewardj   UInt    mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
66208dfdc8a059e35940fe96371360cae39d9724cea9sewardj                        |X86G_CC_MASK_C|X86G_CC_MASK_P;
66218dfdc8a059e35940fe96371360cae39d9724cea9sewardj
66228dfdc8a059e35940fe96371360cae39d9724cea9sewardj   IRTemp  flags = newTemp(Ity_I32);
66238dfdc8a059e35940fe96371360cae39d9724cea9sewardj   assign( flags, mk_x86g_calculate_eflags_all() );
66248dfdc8a059e35940fe96371360cae39d9724cea9sewardj
66258dfdc8a059e35940fe96371360cae39d9724cea9sewardj   eax_with_hole
66268dfdc8a059e35940fe96371360cae39d9724cea9sewardj      = binop(Iop_And32, getIReg(4, R_EAX), mkU32(0xFFFF00FF));
66278dfdc8a059e35940fe96371360cae39d9724cea9sewardj   new_byte
66288dfdc8a059e35940fe96371360cae39d9724cea9sewardj      = binop(Iop_Or32, binop(Iop_And32, mkexpr(flags), mkU32(mask_SZACP)),
66298dfdc8a059e35940fe96371360cae39d9724cea9sewardj                        mkU32(1<<1));
66308dfdc8a059e35940fe96371360cae39d9724cea9sewardj   new_eax
66318dfdc8a059e35940fe96371360cae39d9724cea9sewardj      = binop(Iop_Or32, eax_with_hole,
66328dfdc8a059e35940fe96371360cae39d9724cea9sewardj                        binop(Iop_Shl32, new_byte, mkU8(8)));
66338dfdc8a059e35940fe96371360cae39d9724cea9sewardj   putIReg(4, R_EAX, new_eax);
66348dfdc8a059e35940fe96371360cae39d9724cea9sewardj}
66358dfdc8a059e35940fe96371360cae39d9724cea9sewardj
6636458a6f8809554fc459d90043e032f7c579620c97sewardj
6637458a6f8809554fc459d90043e032f7c579620c97sewardjstatic
6638458a6f8809554fc459d90043e032f7c579620c97sewardjUInt dis_cmpxchg_G_E ( UChar       sorb,
6639e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                       Bool        locked,
6640458a6f8809554fc459d90043e032f7c579620c97sewardj                       Int         size,
664152d049186d07991237a825ec88aa7f1f303edb70sewardj                       Int         delta0 )
6642458a6f8809554fc459d90043e032f7c579620c97sewardj{
6643c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
6644458a6f8809554fc459d90043e032f7c579620c97sewardj   Int   len;
6645458a6f8809554fc459d90043e032f7c579620c97sewardj
6646458a6f8809554fc459d90043e032f7c579620c97sewardj   IRType ty    = szToITy(size);
6647458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp acc   = newTemp(ty);
6648458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp src   = newTemp(ty);
6649458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp dest  = newTemp(ty);
6650458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp dest2 = newTemp(ty);
6651458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp acc2  = newTemp(ty);
6652009230b9758291b594e60d7c0243a73d53e81854sewardj   IRTemp cond  = newTemp(Ity_I1);
665392d168d0f2a985ed9f7ae4e6bba9565a13921b31sewardj   IRTemp addr  = IRTemp_INVALID;
6654458a6f8809554fc459d90043e032f7c579620c97sewardj   UChar  rm    = getUChar(delta0);
6655458a6f8809554fc459d90043e032f7c579620c97sewardj
6656e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* There are 3 cases to consider:
6657e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6658e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      reg-reg: ignore any lock prefix, generate sequence based
665999dd03e04a6914d90d5fee727d61d76905334becflorian               on ITE
6660e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6661e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      reg-mem, not locked: ignore any lock prefix, generate sequence
666299dd03e04a6914d90d5fee727d61d76905334becflorian                           based on ITE
6663e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6664e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      reg-mem, locked: use IRCAS
6665e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   */
6666458a6f8809554fc459d90043e032f7c579620c97sewardj   if (epartIsReg(rm)) {
6667e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* case 1 */
6668458a6f8809554fc459d90043e032f7c579620c97sewardj      assign( dest, getIReg(size, eregOfRM(rm)) );
6669458a6f8809554fc459d90043e032f7c579620c97sewardj      delta0++;
6670e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( src, getIReg(size, gregOfRM(rm)) );
6671e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( acc, getIReg(size, R_EAX) );
6672e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6673009230b9758291b594e60d7c0243a73d53e81854sewardj      assign( cond, mk_x86g_calculate_condition(X86CondZ) );
667499dd03e04a6914d90d5fee727d61d76905334becflorian      assign( dest2, IRExpr_ITE(mkexpr(cond), mkexpr(src), mkexpr(dest)) );
667599dd03e04a6914d90d5fee727d61d76905334becflorian      assign( acc2,  IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
6676e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      putIReg(size, R_EAX, mkexpr(acc2));
6677e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      putIReg(size, eregOfRM(rm), mkexpr(dest2));
6678458a6f8809554fc459d90043e032f7c579620c97sewardj      DIP("cmpxchg%c %s,%s\n", nameISize(size),
6679458a6f8809554fc459d90043e032f7c579620c97sewardj                               nameIReg(size,gregOfRM(rm)),
6680458a6f8809554fc459d90043e032f7c579620c97sewardj                               nameIReg(size,eregOfRM(rm)) );
6681e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
6682e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   else if (!epartIsReg(rm) && !locked) {
6683e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* case 2 */
6684458a6f8809554fc459d90043e032f7c579620c97sewardj      addr = disAMode ( &len, sorb, delta0, dis_buf );
6685458a6f8809554fc459d90043e032f7c579620c97sewardj      assign( dest, loadLE(ty, mkexpr(addr)) );
6686458a6f8809554fc459d90043e032f7c579620c97sewardj      delta0 += len;
6687e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( src, getIReg(size, gregOfRM(rm)) );
6688e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( acc, getIReg(size, R_EAX) );
6689e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6690009230b9758291b594e60d7c0243a73d53e81854sewardj      assign( cond, mk_x86g_calculate_condition(X86CondZ) );
669199dd03e04a6914d90d5fee727d61d76905334becflorian      assign( dest2, IRExpr_ITE(mkexpr(cond), mkexpr(src), mkexpr(dest)) );
669299dd03e04a6914d90d5fee727d61d76905334becflorian      assign( acc2,  IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
6693e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      putIReg(size, R_EAX, mkexpr(acc2));
6694e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      storeLE( mkexpr(addr), mkexpr(dest2) );
6695458a6f8809554fc459d90043e032f7c579620c97sewardj      DIP("cmpxchg%c %s,%s\n", nameISize(size),
6696458a6f8809554fc459d90043e032f7c579620c97sewardj                               nameIReg(size,gregOfRM(rm)), dis_buf);
6697458a6f8809554fc459d90043e032f7c579620c97sewardj   }
6698e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   else if (!epartIsReg(rm) && locked) {
6699e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* case 3 */
6700e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* src is new value.  acc is expected value.  dest is old value.
6701e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         Compute success from the output of the IRCAS, and steer the
6702e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         new value for EAX accordingly: in case of success, EAX is
6703e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         unchanged. */
6704e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      addr = disAMode ( &len, sorb, delta0, dis_buf );
6705e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta0 += len;
6706e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( src, getIReg(size, gregOfRM(rm)) );
6707e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( acc, getIReg(size, R_EAX) );
6708e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      stmt( IRStmt_CAS(
6709e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         mkIRCAS( IRTemp_INVALID, dest, Iend_LE, mkexpr(addr),
6710e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  NULL, mkexpr(acc), NULL, mkexpr(src) )
6711e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      ));
6712e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6713009230b9758291b594e60d7c0243a73d53e81854sewardj      assign( cond, mk_x86g_calculate_condition(X86CondZ) );
671499dd03e04a6914d90d5fee727d61d76905334becflorian      assign( acc2,  IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
6715e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      putIReg(size, R_EAX, mkexpr(acc2));
671640d1d2126f109fc8fce807320d06ef2a775c0852sewardj      DIP("cmpxchg%c %s,%s\n", nameISize(size),
671740d1d2126f109fc8fce807320d06ef2a775c0852sewardj                               nameIReg(size,gregOfRM(rm)), dis_buf);
6718458a6f8809554fc459d90043e032f7c579620c97sewardj   }
6719e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   else vassert(0);
6720458a6f8809554fc459d90043e032f7c579620c97sewardj
6721458a6f8809554fc459d90043e032f7c579620c97sewardj   return delta0;
6722458a6f8809554fc459d90043e032f7c579620c97sewardj}
6723458a6f8809554fc459d90043e032f7c579620c97sewardj
6724458a6f8809554fc459d90043e032f7c579620c97sewardj
6725458a6f8809554fc459d90043e032f7c579620c97sewardj/* Handle conditional move instructions of the form
6726458a6f8809554fc459d90043e032f7c579620c97sewardj      cmovcc E(reg-or-mem), G(reg)
6727458a6f8809554fc459d90043e032f7c579620c97sewardj
6728458a6f8809554fc459d90043e032f7c579620c97sewardj   E(src) is reg-or-mem
6729458a6f8809554fc459d90043e032f7c579620c97sewardj   G(dst) is reg.
6730458a6f8809554fc459d90043e032f7c579620c97sewardj
6731458a6f8809554fc459d90043e032f7c579620c97sewardj   If E is reg, -->    GET %E, tmps
6732458a6f8809554fc459d90043e032f7c579620c97sewardj                       GET %G, tmpd
6733458a6f8809554fc459d90043e032f7c579620c97sewardj                       CMOVcc tmps, tmpd
6734458a6f8809554fc459d90043e032f7c579620c97sewardj                       PUT tmpd, %G
6735458a6f8809554fc459d90043e032f7c579620c97sewardj
6736458a6f8809554fc459d90043e032f7c579620c97sewardj   If E is mem  -->    (getAddr E) -> tmpa
6737458a6f8809554fc459d90043e032f7c579620c97sewardj                       LD (tmpa), tmps
6738458a6f8809554fc459d90043e032f7c579620c97sewardj                       GET %G, tmpd
6739458a6f8809554fc459d90043e032f7c579620c97sewardj                       CMOVcc tmps, tmpd
6740458a6f8809554fc459d90043e032f7c579620c97sewardj                       PUT tmpd, %G
6741458a6f8809554fc459d90043e032f7c579620c97sewardj*/
6742458a6f8809554fc459d90043e032f7c579620c97sewardjstatic
6743458a6f8809554fc459d90043e032f7c579620c97sewardjUInt dis_cmov_E_G ( UChar       sorb,
6744458a6f8809554fc459d90043e032f7c579620c97sewardj                    Int         sz,
67452a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                    X86Condcode cond,
674652d049186d07991237a825ec88aa7f1f303edb70sewardj                    Int         delta0 )
6747458a6f8809554fc459d90043e032f7c579620c97sewardj{
6748458a6f8809554fc459d90043e032f7c579620c97sewardj   UChar rm  = getIByte(delta0);
6749c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
6750458a6f8809554fc459d90043e032f7c579620c97sewardj   Int   len;
6751458a6f8809554fc459d90043e032f7c579620c97sewardj
6752883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   IRType ty   = szToITy(sz);
6753458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp tmps = newTemp(ty);
6754458a6f8809554fc459d90043e032f7c579620c97sewardj   IRTemp tmpd = newTemp(ty);
6755458a6f8809554fc459d90043e032f7c579620c97sewardj
6756458a6f8809554fc459d90043e032f7c579620c97sewardj   if (epartIsReg(rm)) {
6757458a6f8809554fc459d90043e032f7c579620c97sewardj      assign( tmps, getIReg(sz, eregOfRM(rm)) );
6758458a6f8809554fc459d90043e032f7c579620c97sewardj      assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6759458a6f8809554fc459d90043e032f7c579620c97sewardj
6760458a6f8809554fc459d90043e032f7c579620c97sewardj      putIReg(sz, gregOfRM(rm),
676199dd03e04a6914d90d5fee727d61d76905334becflorian                  IRExpr_ITE( mk_x86g_calculate_condition(cond),
676299dd03e04a6914d90d5fee727d61d76905334becflorian                              mkexpr(tmps),
676399dd03e04a6914d90d5fee727d61d76905334becflorian                              mkexpr(tmpd) )
6764458a6f8809554fc459d90043e032f7c579620c97sewardj             );
6765458a6f8809554fc459d90043e032f7c579620c97sewardj      DIP("cmov%c%s %s,%s\n", nameISize(sz),
67662a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                              name_X86Condcode(cond),
6767458a6f8809554fc459d90043e032f7c579620c97sewardj                              nameIReg(sz,eregOfRM(rm)),
6768458a6f8809554fc459d90043e032f7c579620c97sewardj                              nameIReg(sz,gregOfRM(rm)));
6769458a6f8809554fc459d90043e032f7c579620c97sewardj      return 1+delta0;
6770458a6f8809554fc459d90043e032f7c579620c97sewardj   }
6771458a6f8809554fc459d90043e032f7c579620c97sewardj
6772458a6f8809554fc459d90043e032f7c579620c97sewardj   /* E refers to memory */
6773458a6f8809554fc459d90043e032f7c579620c97sewardj   {
6774458a6f8809554fc459d90043e032f7c579620c97sewardj      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6775458a6f8809554fc459d90043e032f7c579620c97sewardj      assign( tmps, loadLE(ty, mkexpr(addr)) );
6776458a6f8809554fc459d90043e032f7c579620c97sewardj      assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6777458a6f8809554fc459d90043e032f7c579620c97sewardj
6778458a6f8809554fc459d90043e032f7c579620c97sewardj      putIReg(sz, gregOfRM(rm),
677999dd03e04a6914d90d5fee727d61d76905334becflorian                  IRExpr_ITE( mk_x86g_calculate_condition(cond),
678099dd03e04a6914d90d5fee727d61d76905334becflorian                              mkexpr(tmps),
678199dd03e04a6914d90d5fee727d61d76905334becflorian                              mkexpr(tmpd) )
6782458a6f8809554fc459d90043e032f7c579620c97sewardj             );
6783458a6f8809554fc459d90043e032f7c579620c97sewardj
6784458a6f8809554fc459d90043e032f7c579620c97sewardj      DIP("cmov%c%s %s,%s\n", nameISize(sz),
67852a9ad023890d3b34cf45e429df2a8ae88b419128sewardj                              name_X86Condcode(cond),
6786458a6f8809554fc459d90043e032f7c579620c97sewardj                              dis_buf,
6787458a6f8809554fc459d90043e032f7c579620c97sewardj                              nameIReg(sz,gregOfRM(rm)));
6788458a6f8809554fc459d90043e032f7c579620c97sewardj      return len+delta0;
6789458a6f8809554fc459d90043e032f7c579620c97sewardj   }
6790458a6f8809554fc459d90043e032f7c579620c97sewardj}
6791458a6f8809554fc459d90043e032f7c579620c97sewardj
6792458a6f8809554fc459d90043e032f7c579620c97sewardj
6793883b00b3d97a9873371557d7b1f2ac5db7985e43sewardjstatic
6794e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardjUInt dis_xadd_G_E ( UChar sorb, Bool locked, Int sz, Int delta0,
6795e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                    Bool* decodeOK )
6796883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj{
6797883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   Int   len;
6798883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   UChar rm = getIByte(delta0);
6799c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar dis_buf[50];
6800883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
6801883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   IRType ty    = szToITy(sz);
6802883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   IRTemp tmpd  = newTemp(ty);
6803883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   IRTemp tmpt0 = newTemp(ty);
6804883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   IRTemp tmpt1 = newTemp(ty);
6805883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
6806e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* There are 3 cases to consider:
6807e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6808c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      reg-reg: ignore any lock prefix,
6809c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj               generate 'naive' (non-atomic) sequence
6810e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6811e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      reg-mem, not locked: ignore any lock prefix, generate 'naive'
6812e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           (non-atomic) sequence
6813e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6814e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      reg-mem, locked: use IRCAS
6815e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   */
6816e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
6817883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   if (epartIsReg(rm)) {
6818e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* case 1 */
6819c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      assign( tmpd,  getIReg(sz, eregOfRM(rm)));
6820c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6821c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6822c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj                           mkexpr(tmpd), mkexpr(tmpt0)) );
6823c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6824c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      putIReg(sz, eregOfRM(rm), mkexpr(tmpt1));
6825c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6826c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      DIP("xadd%c %s, %s\n",
6827c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj          nameISize(sz), nameIReg(sz,gregOfRM(rm)),
6828c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj          				 nameIReg(sz,eregOfRM(rm)));
6829c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      *decodeOK = True;
6830c2433a85f6f0781f3d83b128a15b95f2307a5ddcsewardj      return 1+delta0;
6831e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
6832e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   else if (!epartIsReg(rm) && !locked) {
6833e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* case 2 */
6834e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6835e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( tmpd,  loadLE(ty, mkexpr(addr)) );
6836e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6837e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6838e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           mkexpr(tmpd), mkexpr(tmpt0)) );
6839e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      storeLE( mkexpr(addr), mkexpr(tmpt1) );
6840e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6841e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6842883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      DIP("xadd%c %s, %s\n",
6843e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj          nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6844e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      *decodeOK = True;
6845e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      return len+delta0;
6846e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
6847e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   else if (!epartIsReg(rm) && locked) {
6848e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* case 3 */
6849883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6850883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      assign( tmpd,  loadLE(ty, mkexpr(addr)) );
6851883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6852e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6853e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           mkexpr(tmpd), mkexpr(tmpt0)) );
6854e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      casLE( mkexpr(addr), mkexpr(tmpd)/*expVal*/,
6855e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           mkexpr(tmpt1)/*newVal*/, guest_EIP_curr_instr );
68562a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6857883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6858883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      DIP("xadd%c %s, %s\n",
6859883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj          nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
68600092e0d63a749778959b481a734dcbb3fb299766sewardj      *decodeOK = True;
6861883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      return len+delta0;
6862883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   }
6863e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /*UNREACHED*/
6864e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   vassert(0);
6865883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj}
6866883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
6867b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj/* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
6868b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
68697df596b1e36840e2d74c90aa55589934add61ccfsewardjstatic
687052d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_mov_Ew_Sw ( UChar sorb, Int delta0 )
68717df596b1e36840e2d74c90aa55589934add61ccfsewardj{
6872b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   Int    len;
6873b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   IRTemp addr;
6874b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   UChar  rm  = getIByte(delta0);
6875b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   HChar  dis_buf[50];
68767df596b1e36840e2d74c90aa55589934add61ccfsewardj
68777df596b1e36840e2d74c90aa55589934add61ccfsewardj   if (epartIsReg(rm)) {
68787df596b1e36840e2d74c90aa55589934add61ccfsewardj      putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
68797df596b1e36840e2d74c90aa55589934add61ccfsewardj      DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
68807df596b1e36840e2d74c90aa55589934add61ccfsewardj      return 1+delta0;
6881b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   } else {
6882b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      addr = disAMode ( &len, sorb, delta0, dis_buf );
6883b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
6884b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
6885b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      return len+delta0;
68867df596b1e36840e2d74c90aa55589934add61ccfsewardj   }
68877df596b1e36840e2d74c90aa55589934add61ccfsewardj}
68887df596b1e36840e2d74c90aa55589934add61ccfsewardj
6889b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj/* Move 16 bits from G (a segment register) to Ew (ireg or mem).  If
6890b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   dst is ireg and sz==4, zero out top half of it.  */
6891b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
6892063f02f7e77ca024d24786bec402ca296a05bd6esewardjstatic
6893063f02f7e77ca024d24786bec402ca296a05bd6esewardjUInt dis_mov_Sw_Ew ( UChar sorb,
6894063f02f7e77ca024d24786bec402ca296a05bd6esewardj                     Int   sz,
689552d049186d07991237a825ec88aa7f1f303edb70sewardj                     Int   delta0 )
6896063f02f7e77ca024d24786bec402ca296a05bd6esewardj{
6897b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   Int    len;
6898b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   IRTemp addr;
6899b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   UChar  rm  = getIByte(delta0);
6900b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   HChar  dis_buf[50];
6901063f02f7e77ca024d24786bec402ca296a05bd6esewardj
6902063f02f7e77ca024d24786bec402ca296a05bd6esewardj   vassert(sz == 2 || sz == 4);
6903063f02f7e77ca024d24786bec402ca296a05bd6esewardj
6904063f02f7e77ca024d24786bec402ca296a05bd6esewardj   if (epartIsReg(rm)) {
6905063f02f7e77ca024d24786bec402ca296a05bd6esewardj      if (sz == 4)
6906063f02f7e77ca024d24786bec402ca296a05bd6esewardj         putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6907063f02f7e77ca024d24786bec402ca296a05bd6esewardj      else
6908063f02f7e77ca024d24786bec402ca296a05bd6esewardj         putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6909063f02f7e77ca024d24786bec402ca296a05bd6esewardj
6910063f02f7e77ca024d24786bec402ca296a05bd6esewardj      DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6911063f02f7e77ca024d24786bec402ca296a05bd6esewardj      return 1+delta0;
6912b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   } else {
6913b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      addr = disAMode ( &len, sorb, delta0, dis_buf );
6914b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
6915063f02f7e77ca024d24786bec402ca296a05bd6esewardj      DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
6916b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      return len+delta0;
6917063f02f7e77ca024d24786bec402ca296a05bd6esewardj   }
6918063f02f7e77ca024d24786bec402ca296a05bd6esewardj}
6919063f02f7e77ca024d24786bec402ca296a05bd6esewardj
6920063f02f7e77ca024d24786bec402ca296a05bd6esewardj
6921b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardjstatic
6922b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardjvoid dis_push_segreg ( UInt sreg, Int sz )
6923b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj{
6924b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    IRTemp t1 = newTemp(Ity_I16);
6925b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    IRTemp ta = newTemp(Ity_I32);
6926b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    vassert(sz == 2 || sz == 4);
6927b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
6928b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    assign( t1, getSReg(sreg) );
6929b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6930b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    putIReg(4, R_ESP, mkexpr(ta));
6931b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    storeLE( mkexpr(ta), mkexpr(t1) );
6932b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
69335c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj    DIP("push%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
6934b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj}
6935b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
6936b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardjstatic
6937b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardjvoid dis_pop_segreg ( UInt sreg, Int sz )
6938b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj{
6939b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    IRTemp t1 = newTemp(Ity_I16);
6940b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    IRTemp ta = newTemp(Ity_I32);
6941b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    vassert(sz == 2 || sz == 4);
6942b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
6943b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    assign( ta, getIReg(4, R_ESP) );
6944b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
6945b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
6946b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
6947b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj    putSReg( sreg, mkexpr(t1) );
69485c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj    DIP("pop%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
6949b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj}
6950e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
6951e05c42c99a8e01d05096482afdaa3e7460265dc2sewardjstatic
6952c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardjvoid dis_ret ( /*MOD*/DisResult* dres, UInt d32 )
6953e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj{
6954c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   IRTemp t1 = newTemp(Ity_I32);
6955c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   IRTemp t2 = newTemp(Ity_I32);
6956e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   assign(t1, getIReg(4,R_ESP));
6957e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6958e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
6959c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   jmp_treg(dres, Ijk_Ret, t2);
6960c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres->whatNext == Dis_StopHere);
6961e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj}
6962e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
69634cb918d355cef4e7640d374346852db4556f3524sewardj/*------------------------------------------------------------*/
69644cb918d355cef4e7640d374346852db4556f3524sewardj/*--- SSE/SSE2/SSE3 helpers                                ---*/
69654cb918d355cef4e7640d374346852db4556f3524sewardj/*------------------------------------------------------------*/
6966c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
69679571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj/* Indicates whether the op requires a rounding-mode argument.  Note
69689571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   that this covers only vector floating point arithmetic ops, and
69699571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   omits the scalar ones that need rounding modes.  Note also that
69709571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   inconsistencies here will get picked up later by the IR sanity
69719571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   checker, so this isn't correctness-critical. */
69729571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardjstatic Bool requiresRMode ( IROp op )
69739571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj{
69749571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   switch (op) {
69759571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      /* 128 bit ops */
69769571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      case Iop_Add32Fx4: case Iop_Sub32Fx4:
69779571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      case Iop_Mul32Fx4: case Iop_Div32Fx4:
69789571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      case Iop_Add64Fx2: case Iop_Sub64Fx2:
69799571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      case Iop_Mul64Fx2: case Iop_Div64Fx2:
69809571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj         return True;
69819571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      default:
69829571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj         break;
69839571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   }
69849571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj   return False;
69859571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj}
69869571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj
69879571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj
6988129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj/* Worker function; do not call directly.
6989129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   Handles full width G = G `op` E   and   G = (not G) `op` E.
6990129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj*/
6991129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
6992129b3d9da92af2ad2c58ffacb977aa5766211f08sewardjstatic UInt dis_SSE_E_to_G_all_wrk (
699352d049186d07991237a825ec88aa7f1f303edb70sewardj               UChar sorb, Int delta,
699455085f8680acc89d727e321f3b34cae1a8c4093aflorian               const HChar* opname, IROp op,
69951e6ad745ebafd0524da1da27a4b85524fa84f777sewardj               Bool   invertG
69961e6ad745ebafd0524da1da27a4b85524fa84f777sewardj            )
6997c9a43665879a03886b27a65b68af2a2c11b04f59sewardj{
69981e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   HChar   dis_buf[50];
69991e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   Int     alen;
70001e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   IRTemp  addr;
70011e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   UChar   rm = getIByte(delta);
70021e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   IRExpr* gpart
7003f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRM(rm)))
70041e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                : getXMMReg(gregOfRM(rm));
7005c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   if (epartIsReg(rm)) {
70069571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      putXMMReg(
70079571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj         gregOfRM(rm),
70089571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj         requiresRMode(op)
70099571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj            ? triop(op, get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
70109571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                        gpart,
70119571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                        getXMMReg(eregOfRM(rm)))
70129571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj            : binop(op, gpart,
70139571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                        getXMMReg(eregOfRM(rm)))
70149571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      );
7015c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      DIP("%s %s,%s\n", opname,
7016c9a43665879a03886b27a65b68af2a2c11b04f59sewardj                        nameXMMReg(eregOfRM(rm)),
7017c9a43665879a03886b27a65b68af2a2c11b04f59sewardj                        nameXMMReg(gregOfRM(rm)) );
7018c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      return delta+1;
7019c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   } else {
70201e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
70219571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      putXMMReg(
70229571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj         gregOfRM(rm),
70239571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj         requiresRMode(op)
70249571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj            ? triop(op, get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
70259571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                        gpart,
70269571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                        loadLE(Ity_V128, mkexpr(addr)))
70279571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj            : binop(op, gpart,
70289571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                        loadLE(Ity_V128, mkexpr(addr)))
70299571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      );
70301e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      DIP("%s %s,%s\n", opname,
70311e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                        dis_buf,
70321e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                        nameXMMReg(gregOfRM(rm)) );
70331e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      return delta+alen;
7034c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   }
7035c9a43665879a03886b27a65b68af2a2c11b04f59sewardj}
7036c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
7037129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
7038129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj/* All lanes SSE binary operation, G = G `op` E. */
7039129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
70401e6ad745ebafd0524da1da27a4b85524fa84f777sewardjstatic
704155085f8680acc89d727e321f3b34cae1a8c4093aflorianUInt dis_SSE_E_to_G_all ( UChar sorb, Int delta, const HChar* opname, IROp op )
70421e6ad745ebafd0524da1da27a4b85524fa84f777sewardj{
7043129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
70441e6ad745ebafd0524da1da27a4b85524fa84f777sewardj}
70451e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
7046129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj/* All lanes SSE binary operation, G = (not G) `op` E. */
7047129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
70481e6ad745ebafd0524da1da27a4b85524fa84f777sewardjstatic
704952d049186d07991237a825ec88aa7f1f303edb70sewardjUInt dis_SSE_E_to_G_all_invG ( UChar sorb, Int delta,
705055085f8680acc89d727e321f3b34cae1a8c4093aflorian                               const HChar* opname, IROp op )
70511e6ad745ebafd0524da1da27a4b85524fa84f777sewardj{
7052129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
70531e6ad745ebafd0524da1da27a4b85524fa84f777sewardj}
70541e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
7055164f9275c465cd09ecd09276b8542282f5def250sewardj
7056129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
7057129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
705852d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt dis_SSE_E_to_G_lo32 ( UChar sorb, Int delta,
705955085f8680acc89d727e321f3b34cae1a8c4093aflorian                                  const HChar* opname, IROp op )
7060129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj{
7061129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   HChar   dis_buf[50];
7062129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   Int     alen;
7063129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   IRTemp  addr;
7064129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   UChar   rm = getIByte(delta);
7065129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   IRExpr* gpart = getXMMReg(gregOfRM(rm));
7066129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   if (epartIsReg(rm)) {
7067129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      putXMMReg( gregOfRM(rm),
7068129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                 binop(op, gpart,
7069129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                           getXMMReg(eregOfRM(rm))) );
7070129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      DIP("%s %s,%s\n", opname,
7071129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        nameXMMReg(eregOfRM(rm)),
7072129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        nameXMMReg(gregOfRM(rm)) );
7073129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      return delta+1;
7074129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   } else {
7075129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      /* We can only do a 32-bit memory read, so the upper 3/4 of the
7076129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj         E operand needs to be made simply of zeroes. */
7077129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      IRTemp epart = newTemp(Ity_V128);
7078129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
7079f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( epart, unop( Iop_32UtoV128,
7080129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                           loadLE(Ity_I32, mkexpr(addr))) );
7081129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      putXMMReg( gregOfRM(rm),
7082129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                 binop(op, gpart, mkexpr(epart)) );
7083129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      DIP("%s %s,%s\n", opname,
7084129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        dis_buf,
7085129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        nameXMMReg(gregOfRM(rm)) );
7086129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      return delta+alen;
7087129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   }
7088129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj}
7089129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
7090164f9275c465cd09ecd09276b8542282f5def250sewardj
7091636ad762e49597ef608323f27c7b8eb66962cd90sewardj/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
7092636ad762e49597ef608323f27c7b8eb66962cd90sewardj
709352d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt dis_SSE_E_to_G_lo64 ( UChar sorb, Int delta,
709455085f8680acc89d727e321f3b34cae1a8c4093aflorian                                  const HChar* opname, IROp op )
7095636ad762e49597ef608323f27c7b8eb66962cd90sewardj{
7096636ad762e49597ef608323f27c7b8eb66962cd90sewardj   HChar   dis_buf[50];
7097636ad762e49597ef608323f27c7b8eb66962cd90sewardj   Int     alen;
7098636ad762e49597ef608323f27c7b8eb66962cd90sewardj   IRTemp  addr;
7099636ad762e49597ef608323f27c7b8eb66962cd90sewardj   UChar   rm = getIByte(delta);
7100636ad762e49597ef608323f27c7b8eb66962cd90sewardj   IRExpr* gpart = getXMMReg(gregOfRM(rm));
7101636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (epartIsReg(rm)) {
7102636ad762e49597ef608323f27c7b8eb66962cd90sewardj      putXMMReg( gregOfRM(rm),
7103636ad762e49597ef608323f27c7b8eb66962cd90sewardj                 binop(op, gpart,
7104636ad762e49597ef608323f27c7b8eb66962cd90sewardj                           getXMMReg(eregOfRM(rm))) );
7105636ad762e49597ef608323f27c7b8eb66962cd90sewardj      DIP("%s %s,%s\n", opname,
7106636ad762e49597ef608323f27c7b8eb66962cd90sewardj                        nameXMMReg(eregOfRM(rm)),
7107636ad762e49597ef608323f27c7b8eb66962cd90sewardj                        nameXMMReg(gregOfRM(rm)) );
7108636ad762e49597ef608323f27c7b8eb66962cd90sewardj      return delta+1;
7109636ad762e49597ef608323f27c7b8eb66962cd90sewardj   } else {
7110636ad762e49597ef608323f27c7b8eb66962cd90sewardj      /* We can only do a 64-bit memory read, so the upper half of the
7111636ad762e49597ef608323f27c7b8eb66962cd90sewardj         E operand needs to be made simply of zeroes. */
7112636ad762e49597ef608323f27c7b8eb66962cd90sewardj      IRTemp epart = newTemp(Ity_V128);
7113636ad762e49597ef608323f27c7b8eb66962cd90sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
7114f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( epart, unop( Iop_64UtoV128,
7115636ad762e49597ef608323f27c7b8eb66962cd90sewardj                           loadLE(Ity_I64, mkexpr(addr))) );
7116636ad762e49597ef608323f27c7b8eb66962cd90sewardj      putXMMReg( gregOfRM(rm),
7117636ad762e49597ef608323f27c7b8eb66962cd90sewardj                 binop(op, gpart, mkexpr(epart)) );
7118636ad762e49597ef608323f27c7b8eb66962cd90sewardj      DIP("%s %s,%s\n", opname,
7119636ad762e49597ef608323f27c7b8eb66962cd90sewardj                        dis_buf,
7120636ad762e49597ef608323f27c7b8eb66962cd90sewardj                        nameXMMReg(gregOfRM(rm)) );
7121636ad762e49597ef608323f27c7b8eb66962cd90sewardj      return delta+alen;
7122636ad762e49597ef608323f27c7b8eb66962cd90sewardj   }
7123636ad762e49597ef608323f27c7b8eb66962cd90sewardj}
7124636ad762e49597ef608323f27c7b8eb66962cd90sewardj
7125164f9275c465cd09ecd09276b8542282f5def250sewardj
7126129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj/* All lanes unary SSE operation, G = op(E). */
7127129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
7128129b3d9da92af2ad2c58ffacb977aa5766211f08sewardjstatic UInt dis_SSE_E_to_G_unary_all (
712952d049186d07991237a825ec88aa7f1f303edb70sewardj               UChar sorb, Int delta,
713055085f8680acc89d727e321f3b34cae1a8c4093aflorian               const HChar* opname, IROp op
71310bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj            )
71320bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj{
71330bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   HChar   dis_buf[50];
71340bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   Int     alen;
71350bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   IRTemp  addr;
71360bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   UChar   rm = getIByte(delta);
71378bb1c9e03843a0a9d939279b738f280919bce8cbsewardj   // Sqrt32Fx4 and Sqrt64Fx2 take a rounding mode, which is faked
71388bb1c9e03843a0a9d939279b738f280919bce8cbsewardj   // up in the usual way.
71398bb1c9e03843a0a9d939279b738f280919bce8cbsewardj   Bool needsIRRM = op == Iop_Sqrt32Fx4 || op == Iop_Sqrt64Fx2;
71400bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   if (epartIsReg(rm)) {
71418bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      IRExpr* src = getXMMReg(eregOfRM(rm));
71428bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      /* XXXROUNDINGFIXME */
71438bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      IRExpr* res = needsIRRM ? binop(op, get_FAKE_roundingmode(), src)
71448bb1c9e03843a0a9d939279b738f280919bce8cbsewardj                              : unop(op, src);
71458bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      putXMMReg( gregOfRM(rm), res );
71460bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      DIP("%s %s,%s\n", opname,
71470bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj                        nameXMMReg(eregOfRM(rm)),
71480bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj                        nameXMMReg(gregOfRM(rm)) );
71490bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      return delta+1;
71500bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   } else {
71510bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
71528bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      IRExpr* src = loadLE(Ity_V128, mkexpr(addr));
71538bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      /* XXXROUNDINGFIXME */
71548bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      IRExpr* res = needsIRRM ? binop(op, get_FAKE_roundingmode(), src)
71558bb1c9e03843a0a9d939279b738f280919bce8cbsewardj                              : unop(op, src);
71568bb1c9e03843a0a9d939279b738f280919bce8cbsewardj      putXMMReg( gregOfRM(rm), res );
71570bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      DIP("%s %s,%s\n", opname,
71580bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj                        dis_buf,
71590bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj                        nameXMMReg(gregOfRM(rm)) );
71600bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      return delta+alen;
71610bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
71620bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj}
71630bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
7164164f9275c465cd09ecd09276b8542282f5def250sewardj
7165129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
71660bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
7167129b3d9da92af2ad2c58ffacb977aa5766211f08sewardjstatic UInt dis_SSE_E_to_G_unary_lo32 (
716852d049186d07991237a825ec88aa7f1f303edb70sewardj               UChar sorb, Int delta,
716955085f8680acc89d727e321f3b34cae1a8c4093aflorian               const HChar* opname, IROp op
7170129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj            )
7171129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj{
7172129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   /* First we need to get the old G value and patch the low 32 bits
7173129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      of the E operand into it.  Then apply op and write back to G. */
7174129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   HChar   dis_buf[50];
7175129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   Int     alen;
7176129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   IRTemp  addr;
7177129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   UChar   rm = getIByte(delta);
7178129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   IRTemp  oldG0 = newTemp(Ity_V128);
7179129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   IRTemp  oldG1 = newTemp(Ity_V128);
7180129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
7181129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   assign( oldG0, getXMMReg(gregOfRM(rm)) );
7182129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
7183129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   if (epartIsReg(rm)) {
7184129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      assign( oldG1,
7185f0c1c58d6e47608ce166058997f795f1d7d45127sewardj              binop( Iop_SetV128lo32,
7186129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                     mkexpr(oldG0),
718735579be3fac7bf13b1e2bf39470475aa5332b6d7sewardj                     getXMMRegLane32(eregOfRM(rm), 0)) );
7188129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7189129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      DIP("%s %s,%s\n", opname,
7190129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        nameXMMReg(eregOfRM(rm)),
7191129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        nameXMMReg(gregOfRM(rm)) );
7192129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      return delta+1;
7193129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   } else {
7194129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
7195129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      assign( oldG1,
7196f0c1c58d6e47608ce166058997f795f1d7d45127sewardj              binop( Iop_SetV128lo32,
7197129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                     mkexpr(oldG0),
7198129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                     loadLE(Ity_I32, mkexpr(addr)) ));
7199129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7200129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      DIP("%s %s,%s\n", opname,
7201129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        dis_buf,
7202129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj                        nameXMMReg(gregOfRM(rm)) );
7203129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      return delta+alen;
7204129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj   }
7205129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj}
7206129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
7207164f9275c465cd09ecd09276b8542282f5def250sewardj
7208008754b1685e50d117f9c982ddeeafbaca151bfesewardj/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7209008754b1685e50d117f9c982ddeeafbaca151bfesewardj
7210008754b1685e50d117f9c982ddeeafbaca151bfesewardjstatic UInt dis_SSE_E_to_G_unary_lo64 (
721152d049186d07991237a825ec88aa7f1f303edb70sewardj               UChar sorb, Int delta,
721255085f8680acc89d727e321f3b34cae1a8c4093aflorian               const HChar* opname, IROp op
7213008754b1685e50d117f9c982ddeeafbaca151bfesewardj            )
7214008754b1685e50d117f9c982ddeeafbaca151bfesewardj{
7215008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* First we need to get the old G value and patch the low 64 bits
7216008754b1685e50d117f9c982ddeeafbaca151bfesewardj      of the E operand into it.  Then apply op and write back to G. */
7217008754b1685e50d117f9c982ddeeafbaca151bfesewardj   HChar   dis_buf[50];
7218008754b1685e50d117f9c982ddeeafbaca151bfesewardj   Int     alen;
7219008754b1685e50d117f9c982ddeeafbaca151bfesewardj   IRTemp  addr;
7220008754b1685e50d117f9c982ddeeafbaca151bfesewardj   UChar   rm = getIByte(delta);
7221008754b1685e50d117f9c982ddeeafbaca151bfesewardj   IRTemp  oldG0 = newTemp(Ity_V128);
7222008754b1685e50d117f9c982ddeeafbaca151bfesewardj   IRTemp  oldG1 = newTemp(Ity_V128);
7223008754b1685e50d117f9c982ddeeafbaca151bfesewardj
7224008754b1685e50d117f9c982ddeeafbaca151bfesewardj   assign( oldG0, getXMMReg(gregOfRM(rm)) );
7225008754b1685e50d117f9c982ddeeafbaca151bfesewardj
7226008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (epartIsReg(rm)) {
7227008754b1685e50d117f9c982ddeeafbaca151bfesewardj      assign( oldG1,
7228f0c1c58d6e47608ce166058997f795f1d7d45127sewardj              binop( Iop_SetV128lo64,
7229008754b1685e50d117f9c982ddeeafbaca151bfesewardj                     mkexpr(oldG0),
7230008754b1685e50d117f9c982ddeeafbaca151bfesewardj                     getXMMRegLane64(eregOfRM(rm), 0)) );
7231008754b1685e50d117f9c982ddeeafbaca151bfesewardj      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7232008754b1685e50d117f9c982ddeeafbaca151bfesewardj      DIP("%s %s,%s\n", opname,
7233008754b1685e50d117f9c982ddeeafbaca151bfesewardj                        nameXMMReg(eregOfRM(rm)),
7234008754b1685e50d117f9c982ddeeafbaca151bfesewardj                        nameXMMReg(gregOfRM(rm)) );
7235008754b1685e50d117f9c982ddeeafbaca151bfesewardj      return delta+1;
7236008754b1685e50d117f9c982ddeeafbaca151bfesewardj   } else {
7237008754b1685e50d117f9c982ddeeafbaca151bfesewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
7238008754b1685e50d117f9c982ddeeafbaca151bfesewardj      assign( oldG1,
7239f0c1c58d6e47608ce166058997f795f1d7d45127sewardj              binop( Iop_SetV128lo64,
7240008754b1685e50d117f9c982ddeeafbaca151bfesewardj                     mkexpr(oldG0),
7241008754b1685e50d117f9c982ddeeafbaca151bfesewardj                     loadLE(Ity_I64, mkexpr(addr)) ));
7242008754b1685e50d117f9c982ddeeafbaca151bfesewardj      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7243008754b1685e50d117f9c982ddeeafbaca151bfesewardj      DIP("%s %s,%s\n", opname,
7244008754b1685e50d117f9c982ddeeafbaca151bfesewardj                        dis_buf,
7245008754b1685e50d117f9c982ddeeafbaca151bfesewardj                        nameXMMReg(gregOfRM(rm)) );
7246008754b1685e50d117f9c982ddeeafbaca151bfesewardj      return delta+alen;
7247008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
7248008754b1685e50d117f9c982ddeeafbaca151bfesewardj}
7249008754b1685e50d117f9c982ddeeafbaca151bfesewardj
7250164f9275c465cd09ecd09276b8542282f5def250sewardj
7251164f9275c465cd09ecd09276b8542282f5def250sewardj/* SSE integer binary operation:
7252164f9275c465cd09ecd09276b8542282f5def250sewardj      G = G `op` E   (eLeft == False)
7253164f9275c465cd09ecd09276b8542282f5def250sewardj      G = E `op` G   (eLeft == True)
7254164f9275c465cd09ecd09276b8542282f5def250sewardj*/
7255164f9275c465cd09ecd09276b8542282f5def250sewardjstatic UInt dis_SSEint_E_to_G(
725652d049186d07991237a825ec88aa7f1f303edb70sewardj               UChar sorb, Int delta,
725755085f8680acc89d727e321f3b34cae1a8c4093aflorian               const HChar* opname, IROp op,
7258164f9275c465cd09ecd09276b8542282f5def250sewardj               Bool   eLeft
7259164f9275c465cd09ecd09276b8542282f5def250sewardj            )
7260164f9275c465cd09ecd09276b8542282f5def250sewardj{
7261164f9275c465cd09ecd09276b8542282f5def250sewardj   HChar   dis_buf[50];
7262164f9275c465cd09ecd09276b8542282f5def250sewardj   Int     alen;
7263164f9275c465cd09ecd09276b8542282f5def250sewardj   IRTemp  addr;
7264164f9275c465cd09ecd09276b8542282f5def250sewardj   UChar   rm = getIByte(delta);
7265164f9275c465cd09ecd09276b8542282f5def250sewardj   IRExpr* gpart = getXMMReg(gregOfRM(rm));
7266164f9275c465cd09ecd09276b8542282f5def250sewardj   IRExpr* epart = NULL;
7267164f9275c465cd09ecd09276b8542282f5def250sewardj   if (epartIsReg(rm)) {
7268164f9275c465cd09ecd09276b8542282f5def250sewardj      epart = getXMMReg(eregOfRM(rm));
7269164f9275c465cd09ecd09276b8542282f5def250sewardj      DIP("%s %s,%s\n", opname,
7270164f9275c465cd09ecd09276b8542282f5def250sewardj                        nameXMMReg(eregOfRM(rm)),
7271164f9275c465cd09ecd09276b8542282f5def250sewardj                        nameXMMReg(gregOfRM(rm)) );
7272164f9275c465cd09ecd09276b8542282f5def250sewardj      delta += 1;
7273164f9275c465cd09ecd09276b8542282f5def250sewardj   } else {
7274164f9275c465cd09ecd09276b8542282f5def250sewardj      addr  = disAMode ( &alen, sorb, delta, dis_buf );
7275164f9275c465cd09ecd09276b8542282f5def250sewardj      epart = loadLE(Ity_V128, mkexpr(addr));
7276164f9275c465cd09ecd09276b8542282f5def250sewardj      DIP("%s %s,%s\n", opname,
7277164f9275c465cd09ecd09276b8542282f5def250sewardj                        dis_buf,
7278164f9275c465cd09ecd09276b8542282f5def250sewardj                        nameXMMReg(gregOfRM(rm)) );
7279164f9275c465cd09ecd09276b8542282f5def250sewardj      delta += alen;
7280164f9275c465cd09ecd09276b8542282f5def250sewardj   }
7281164f9275c465cd09ecd09276b8542282f5def250sewardj   putXMMReg( gregOfRM(rm),
7282164f9275c465cd09ecd09276b8542282f5def250sewardj              eLeft ? binop(op, epart, gpart)
7283164f9275c465cd09ecd09276b8542282f5def250sewardj	            : binop(op, gpart, epart) );
7284164f9275c465cd09ecd09276b8542282f5def250sewardj   return delta;
7285164f9275c465cd09ecd09276b8542282f5def250sewardj}
7286164f9275c465cd09ecd09276b8542282f5def250sewardj
7287164f9275c465cd09ecd09276b8542282f5def250sewardj
7288fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj/* Helper for doing SSE FP comparisons. */
72890bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
72901e6ad745ebafd0524da1da27a4b85524fa84f777sewardjstatic void findSSECmpOp ( Bool* needNot, IROp* op,
72911e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                           Int imm8, Bool all_lanes, Int sz )
72921e6ad745ebafd0524da1da27a4b85524fa84f777sewardj{
72931e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   imm8 &= 7;
72941e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   *needNot = False;
72951e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   *op      = Iop_INVALID;
72961e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   if (imm8 >= 4) {
72971e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      *needNot = True;
72981e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      imm8 -= 4;
72991e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
73001e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
73011e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   if (sz == 4 && all_lanes) {
73021e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      switch (imm8) {
73031e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 0: *op = Iop_CmpEQ32Fx4; return;
73041e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 1: *op = Iop_CmpLT32Fx4; return;
73051e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 2: *op = Iop_CmpLE32Fx4; return;
73061e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 3: *op = Iop_CmpUN32Fx4; return;
73071e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         default: break;
73081e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      }
73091e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
73101e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   if (sz == 4 && !all_lanes) {
73111e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      switch (imm8) {
73121e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 0: *op = Iop_CmpEQ32F0x4; return;
73131e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 1: *op = Iop_CmpLT32F0x4; return;
73141e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 2: *op = Iop_CmpLE32F0x4; return;
73151e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         case 3: *op = Iop_CmpUN32F0x4; return;
73161e6ad745ebafd0524da1da27a4b85524fa84f777sewardj         default: break;
73171e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      }
73181e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
7319fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 8 && all_lanes) {
7320fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      switch (imm8) {
7321fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 0: *op = Iop_CmpEQ64Fx2; return;
7322fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 1: *op = Iop_CmpLT64Fx2; return;
7323fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 2: *op = Iop_CmpLE64Fx2; return;
7324fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 3: *op = Iop_CmpUN64Fx2; return;
7325fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         default: break;
7326fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
7327fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
7328fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 8 && !all_lanes) {
7329fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      switch (imm8) {
7330fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 0: *op = Iop_CmpEQ64F0x2; return;
7331fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 1: *op = Iop_CmpLT64F0x2; return;
7332fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 2: *op = Iop_CmpLE64F0x2; return;
7333fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         case 3: *op = Iop_CmpUN64F0x2; return;
7334fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         default: break;
7335fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
73361e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
73371e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   vpanic("findSSECmpOp(x86,guest)");
73381e6ad745ebafd0524da1da27a4b85524fa84f777sewardj}
73391e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
734033c69e5236ab884bd8ce9491432d4d00a6b95389sewardj/* Handles SSE 32F/64F comparisons. */
7341129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj
734252d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt dis_SSEcmp_E_to_G ( UChar sorb, Int delta,
734355085f8680acc89d727e321f3b34cae1a8c4093aflorian				const HChar* opname, Bool all_lanes, Int sz )
73441e6ad745ebafd0524da1da27a4b85524fa84f777sewardj{
73451e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   HChar   dis_buf[50];
73461e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   Int     alen, imm8;
73471e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   IRTemp  addr;
73481e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   Bool    needNot = False;
73491e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   IROp    op      = Iop_INVALID;
73501e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   IRTemp  plain   = newTemp(Ity_V128);
73511e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   UChar   rm      = getIByte(delta);
73521e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   UShort  mask    = 0;
73531e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   vassert(sz == 4 || sz == 8);
73541e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   if (epartIsReg(rm)) {
73551e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      imm8 = getIByte(delta+1);
73561e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
73571e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
73581e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                               getXMMReg(eregOfRM(rm))) );
73591e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      delta += 2;
73601e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      DIP("%s $%d,%s,%s\n", opname,
73611e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                            (Int)imm8,
73621e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                            nameXMMReg(eregOfRM(rm)),
73631e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                            nameXMMReg(gregOfRM(rm)) );
73641e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   } else {
73651e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
73661e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      imm8 = getIByte(delta+alen);
73671e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
736833c69e5236ab884bd8ce9491432d4d00a6b95389sewardj      assign( plain,
736933c69e5236ab884bd8ce9491432d4d00a6b95389sewardj              binop(
737033c69e5236ab884bd8ce9491432d4d00a6b95389sewardj                 op,
737133c69e5236ab884bd8ce9491432d4d00a6b95389sewardj                 getXMMReg(gregOfRM(rm)),
737233c69e5236ab884bd8ce9491432d4d00a6b95389sewardj                   all_lanes  ? loadLE(Ity_V128, mkexpr(addr))
737333c69e5236ab884bd8ce9491432d4d00a6b95389sewardj                 : sz == 8    ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
737433c69e5236ab884bd8ce9491432d4d00a6b95389sewardj                 : /*sz==4*/    unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
737533c69e5236ab884bd8ce9491432d4d00a6b95389sewardj             )
737633c69e5236ab884bd8ce9491432d4d00a6b95389sewardj      );
73771e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      delta += alen+1;
73781e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      DIP("%s $%d,%s,%s\n", opname,
73791e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                            (Int)imm8,
73801e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                            dis_buf,
73811e6ad745ebafd0524da1da27a4b85524fa84f777sewardj                            nameXMMReg(gregOfRM(rm)) );
73821e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
73831e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
73842e38386d2f5902feed6ec276c2c2292a137717b9sewardj   if (needNot && all_lanes) {
73852e38386d2f5902feed6ec276c2c2292a137717b9sewardj      putXMMReg( gregOfRM(rm),
7386f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                 unop(Iop_NotV128, mkexpr(plain)) );
73872e38386d2f5902feed6ec276c2c2292a137717b9sewardj   }
73882e38386d2f5902feed6ec276c2c2292a137717b9sewardj   else
73892e38386d2f5902feed6ec276c2c2292a137717b9sewardj   if (needNot && !all_lanes) {
73909b45b48e80f4e23bc72cbefdcb94a4258d22488fsewardj      mask = toUShort( sz==4 ? 0x000F : 0x00FF );
73912e38386d2f5902feed6ec276c2c2292a137717b9sewardj      putXMMReg( gregOfRM(rm),
7392f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
73932e38386d2f5902feed6ec276c2c2292a137717b9sewardj   }
73942e38386d2f5902feed6ec276c2c2292a137717b9sewardj   else {
73952e38386d2f5902feed6ec276c2c2292a137717b9sewardj      putXMMReg( gregOfRM(rm), mkexpr(plain) );
73962e38386d2f5902feed6ec276c2c2292a137717b9sewardj   }
73971e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
73981e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   return delta;
73991e6ad745ebafd0524da1da27a4b85524fa84f777sewardj}
74001e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
7401b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7402b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj/* Vector by scalar shift of G by the amount specified at the bottom
7403b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   of E. */
7404b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
740552d049186d07991237a825ec88aa7f1f303edb70sewardjstatic UInt dis_SSE_shiftG_byE ( UChar sorb, Int delta,
740655085f8680acc89d727e321f3b34cae1a8c4093aflorian                                 const HChar* opname, IROp op )
7407b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj{
7408b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   HChar   dis_buf[50];
7409b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   Int     alen, size;
7410b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp  addr;
7411b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   Bool    shl, shr, sar;
7412b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   UChar   rm   = getIByte(delta);
7413b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp  g0   = newTemp(Ity_V128);
7414b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp  g1   = newTemp(Ity_V128);
7415b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp  amt  = newTemp(Ity_I32);
7416b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp  amt8 = newTemp(Ity_I8);
7417b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (epartIsReg(rm)) {
7418b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
7419b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      DIP("%s %s,%s\n", opname,
7420b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                        nameXMMReg(eregOfRM(rm)),
7421b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                        nameXMMReg(gregOfRM(rm)) );
7422b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta++;
7423b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   } else {
7424b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      addr = disAMode ( &alen, sorb, delta, dis_buf );
7425b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
7426b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      DIP("%s %s,%s\n", opname,
7427b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                        dis_buf,
7428b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                        nameXMMReg(gregOfRM(rm)) );
7429b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta += alen;
7430b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
7431b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( g0,   getXMMReg(gregOfRM(rm)) );
7432b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
7433b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7434b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   shl = shr = sar = False;
7435b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   size = 0;
7436b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   switch (op) {
7437b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShlN16x8: shl = True; size = 32; break;
7438b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShlN32x4: shl = True; size = 32; break;
7439b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShlN64x2: shl = True; size = 64; break;
7440b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_SarN16x8: sar = True; size = 16; break;
7441b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_SarN32x4: sar = True; size = 32; break;
7442b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShrN16x8: shr = True; size = 16; break;
7443b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShrN32x4: shr = True; size = 32; break;
7444b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShrN64x2: shr = True; size = 64; break;
7445b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      default: vassert(0);
7446b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
7447b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7448b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (shl || shr) {
7449b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj     assign(
7450b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj        g1,
745199dd03e04a6914d90d5fee727d61d76905334becflorian        IRExpr_ITE(
7452009230b9758291b594e60d7c0243a73d53e81854sewardj           binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
745399dd03e04a6914d90d5fee727d61d76905334becflorian           binop(op, mkexpr(g0), mkexpr(amt8)),
745499dd03e04a6914d90d5fee727d61d76905334becflorian           mkV128(0x0000)
7455b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj        )
7456b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj     );
7457b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   } else
7458b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sar) {
7459b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj     assign(
7460b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj        g1,
746199dd03e04a6914d90d5fee727d61d76905334becflorian        IRExpr_ITE(
7462009230b9758291b594e60d7c0243a73d53e81854sewardj           binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
746399dd03e04a6914d90d5fee727d61d76905334becflorian           binop(op, mkexpr(g0), mkexpr(amt8)),
746499dd03e04a6914d90d5fee727d61d76905334becflorian           binop(op, mkexpr(g0), mkU8(size-1))
7465b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj        )
7466b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj     );
7467b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   } else {
7468ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      /*NOTREACHED*/
7469b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      vassert(0);
7470b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
7471b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7472b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   putXMMReg( gregOfRM(rm), mkexpr(g1) );
7473b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   return delta;
7474b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj}
7475b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7476b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7477b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj/* Vector by scalar shift of E by an immediate byte. */
7478b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
747938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardjstatic
748055085f8680acc89d727e321f3b34cae1a8c4093aflorianUInt dis_SSE_shiftE_imm ( Int delta, const HChar* opname, IROp op )
7481b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj{
7482b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   Bool    shl, shr, sar;
7483b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   UChar   rm   = getIByte(delta);
748438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  e0   = newTemp(Ity_V128);
748538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   IRTemp  e1   = newTemp(Ity_V128);
7486b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   UChar   amt, size;
7487b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   vassert(epartIsReg(rm));
7488b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   vassert(gregOfRM(rm) == 2
7489b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj           || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
74902d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj   amt = getIByte(delta+1);
7491b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   delta += 2;
7492b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   DIP("%s $%d,%s\n", opname,
7493b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                      (Int)amt,
7494b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                      nameXMMReg(eregOfRM(rm)) );
749538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   assign( e0, getXMMReg(eregOfRM(rm)) );
7496b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7497b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   shl = shr = sar = False;
7498b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   size = 0;
7499b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   switch (op) {
7500b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShlN16x8: shl = True; size = 16; break;
7501b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShlN32x4: shl = True; size = 32; break;
7502b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShlN64x2: shl = True; size = 64; break;
7503b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_SarN16x8: sar = True; size = 16; break;
7504b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_SarN32x4: sar = True; size = 32; break;
7505b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShrN16x8: shr = True; size = 16; break;
7506b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShrN32x4: shr = True; size = 32; break;
7507b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      case Iop_ShrN64x2: shr = True; size = 64; break;
7508b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      default: vassert(0);
7509b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
7510b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7511b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (shl || shr) {
7512ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      assign( e1, amt >= size
7513ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     ? mkV128(0x0000)
7514ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     : binop(op, mkexpr(e0), mkU8(amt))
7515ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      );
7516b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   } else
7517b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sar) {
7518ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      assign( e1, amt >= size
7519ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     ? binop(op, mkexpr(e0), mkU8(size-1))
7520ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj                     : binop(op, mkexpr(e0), mkU8(amt))
7521ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      );
7522b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   } else {
7523ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      /*NOTREACHED*/
7524b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      vassert(0);
7525b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
7526b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
752738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj   putXMMReg( eregOfRM(rm), mkexpr(e1) );
7528b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   return delta;
7529b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj}
7530b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7531b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7532c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj/* Get the current SSE rounding mode. */
7533c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
75344cb918d355cef4e7640d374346852db4556f3524sewardjstatic IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
75354cb918d355cef4e7640d374346852db4556f3524sewardj{
75364cb918d355cef4e7640d374346852db4556f3524sewardj   return binop( Iop_And32,
75374cb918d355cef4e7640d374346852db4556f3524sewardj                 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
75384cb918d355cef4e7640d374346852db4556f3524sewardj                 mkU32(3) );
75394cb918d355cef4e7640d374346852db4556f3524sewardj}
75404cb918d355cef4e7640d374346852db4556f3524sewardj
7541636ad762e49597ef608323f27c7b8eb66962cd90sewardjstatic void put_sse_roundingmode ( IRExpr* sseround )
7542636ad762e49597ef608323f27c7b8eb66962cd90sewardj{
7543dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   vassert(typeOfIRExpr(irsb->tyenv, sseround) == Ity_I32);
7544636ad762e49597ef608323f27c7b8eb66962cd90sewardj   stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
7545636ad762e49597ef608323f27c7b8eb66962cd90sewardj}
7546636ad762e49597ef608323f27c7b8eb66962cd90sewardj
7547c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj/* Break a 128-bit value up into four 32-bit ints. */
7548c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
7549c1e7dfc9370ee70f7e9f52294c764d4233619927sewardjstatic void breakup128to32s ( IRTemp t128,
7550c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj			      /*OUTs*/
7551c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                              IRTemp* t3, IRTemp* t2,
7552c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                              IRTemp* t1, IRTemp* t0 )
7553c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj{
7554c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   IRTemp hi64 = newTemp(Ity_I64);
7555c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   IRTemp lo64 = newTemp(Ity_I64);
7556f0c1c58d6e47608ce166058997f795f1d7d45127sewardj   assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
7557f0c1c58d6e47608ce166058997f795f1d7d45127sewardj   assign( lo64, unop(Iop_V128to64,   mkexpr(t128)) );
7558c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
7559c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   vassert(t0 && *t0 == IRTemp_INVALID);
7560c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   vassert(t1 && *t1 == IRTemp_INVALID);
7561c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   vassert(t2 && *t2 == IRTemp_INVALID);
7562c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   vassert(t3 && *t3 == IRTemp_INVALID);
7563c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
7564c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   *t0 = newTemp(Ity_I32);
7565c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   *t1 = newTemp(Ity_I32);
7566c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   *t2 = newTemp(Ity_I32);
7567c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   *t3 = newTemp(Ity_I32);
7568c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   assign( *t0, unop(Iop_64to32,   mkexpr(lo64)) );
7569c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
7570c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   assign( *t2, unop(Iop_64to32,   mkexpr(hi64)) );
7571c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
7572c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj}
7573c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
7574c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj/* Construct a 128-bit value from four 32-bit ints. */
7575c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
7576c1e7dfc9370ee70f7e9f52294c764d4233619927sewardjstatic IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
7577c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                              IRTemp t1, IRTemp t0 )
7578c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj{
7579c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   return
7580f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      binop( Iop_64HLtoV128,
7581c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj             binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
7582c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj             binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
7583c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   );
7584c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj}
7585c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
7586b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj/* Break a 64-bit value up into four 16-bit ints. */
7587b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7588b9fa69b4047ef2a1fd822bab909437c920b9c297sewardjstatic void breakup64to16s ( IRTemp t64,
7589b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                             /*OUTs*/
7590b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                             IRTemp* t3, IRTemp* t2,
7591b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                             IRTemp* t1, IRTemp* t0 )
7592b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj{
7593b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp hi32 = newTemp(Ity_I32);
7594b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   IRTemp lo32 = newTemp(Ity_I32);
7595b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
7596b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( lo32, unop(Iop_64to32,   mkexpr(t64)) );
7597b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7598b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   vassert(t0 && *t0 == IRTemp_INVALID);
7599b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   vassert(t1 && *t1 == IRTemp_INVALID);
7600b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   vassert(t2 && *t2 == IRTemp_INVALID);
7601b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   vassert(t3 && *t3 == IRTemp_INVALID);
7602b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7603b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   *t0 = newTemp(Ity_I16);
7604b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   *t1 = newTemp(Ity_I16);
7605b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   *t2 = newTemp(Ity_I16);
7606b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   *t3 = newTemp(Ity_I16);
7607b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( *t0, unop(Iop_32to16,   mkexpr(lo32)) );
7608b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
7609b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( *t2, unop(Iop_32to16,   mkexpr(hi32)) );
7610b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
7611b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj}
7612b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7613b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj/* Construct a 64-bit value from four 16-bit ints. */
7614b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
7615b9fa69b4047ef2a1fd822bab909437c920b9c297sewardjstatic IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
7616b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                             IRTemp t1, IRTemp t0 )
7617b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj{
7618b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   return
7619b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      binop( Iop_32HLto64,
7620b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj             binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7621b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj             binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7622b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   );
7623b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj}
7624b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
76250e9a0f551e190b475150dcd6bc4500033eb05338sewardj/* Generate IR to set the guest %EFLAGS from the pushfl-format image
76260e9a0f551e190b475150dcd6bc4500033eb05338sewardj   in the given 32-bit temporary.  The flags that are set are: O S Z A
76270e9a0f551e190b475150dcd6bc4500033eb05338sewardj   C P D ID AC.
76280e9a0f551e190b475150dcd6bc4500033eb05338sewardj
76290e9a0f551e190b475150dcd6bc4500033eb05338sewardj   In all cases, code to set AC is generated.  However, VEX actually
76300e9a0f551e190b475150dcd6bc4500033eb05338sewardj   ignores the AC value and so can optionally emit an emulation
76310e9a0f551e190b475150dcd6bc4500033eb05338sewardj   warning when it is enabled.  In this routine, an emulation warning
76320e9a0f551e190b475150dcd6bc4500033eb05338sewardj   is only emitted if emit_AC_emwarn is True, in which case
76330e9a0f551e190b475150dcd6bc4500033eb05338sewardj   next_insn_EIP must be correct (this allows for correct code
76340e9a0f551e190b475150dcd6bc4500033eb05338sewardj   generation for popfl/popfw).  If emit_AC_emwarn is False,
76350e9a0f551e190b475150dcd6bc4500033eb05338sewardj   next_insn_EIP is unimportant (this allows for easy if kludgey code
76360e9a0f551e190b475150dcd6bc4500033eb05338sewardj   generation for IRET.) */
76370e9a0f551e190b475150dcd6bc4500033eb05338sewardj
76380e9a0f551e190b475150dcd6bc4500033eb05338sewardjstatic
76390e9a0f551e190b475150dcd6bc4500033eb05338sewardjvoid set_EFLAGS_from_value ( IRTemp t1,
76400e9a0f551e190b475150dcd6bc4500033eb05338sewardj                             Bool   emit_AC_emwarn,
76410e9a0f551e190b475150dcd6bc4500033eb05338sewardj                             Addr32 next_insn_EIP )
76420e9a0f551e190b475150dcd6bc4500033eb05338sewardj{
76430e9a0f551e190b475150dcd6bc4500033eb05338sewardj   vassert(typeOfIRTemp(irsb->tyenv,t1) == Ity_I32);
76440e9a0f551e190b475150dcd6bc4500033eb05338sewardj
76450e9a0f551e190b475150dcd6bc4500033eb05338sewardj   /* t1 is the flag word.  Mask out everything except OSZACP and set
76460e9a0f551e190b475150dcd6bc4500033eb05338sewardj      the flags thunk to X86G_CC_OP_COPY. */
76470e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
76480e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
76490e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put( OFFB_CC_DEP1,
76500e9a0f551e190b475150dcd6bc4500033eb05338sewardj                     binop(Iop_And32,
76510e9a0f551e190b475150dcd6bc4500033eb05338sewardj                           mkexpr(t1),
76520e9a0f551e190b475150dcd6bc4500033eb05338sewardj                           mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
76530e9a0f551e190b475150dcd6bc4500033eb05338sewardj                                  | X86G_CC_MASK_A | X86G_CC_MASK_Z
76540e9a0f551e190b475150dcd6bc4500033eb05338sewardj                                  | X86G_CC_MASK_S| X86G_CC_MASK_O )
76550e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          )
76560e9a0f551e190b475150dcd6bc4500033eb05338sewardj                    )
76570e9a0f551e190b475150dcd6bc4500033eb05338sewardj       );
76580e9a0f551e190b475150dcd6bc4500033eb05338sewardj   /* Set NDEP even though it isn't used.  This makes redundant-PUT
76590e9a0f551e190b475150dcd6bc4500033eb05338sewardj      elimination of previous stores to this field work better. */
76600e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
76610e9a0f551e190b475150dcd6bc4500033eb05338sewardj
76620e9a0f551e190b475150dcd6bc4500033eb05338sewardj   /* Also need to set the D flag, which is held in bit 10 of t1.
76630e9a0f551e190b475150dcd6bc4500033eb05338sewardj      If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
76640e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put(
76650e9a0f551e190b475150dcd6bc4500033eb05338sewardj            OFFB_DFLAG,
766699dd03e04a6914d90d5fee727d61d76905334becflorian            IRExpr_ITE(
7667009230b9758291b594e60d7c0243a73d53e81854sewardj               unop(Iop_32to1,
76680e9a0f551e190b475150dcd6bc4500033eb05338sewardj                    binop(Iop_And32,
76690e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
76700e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          mkU32(1))),
767199dd03e04a6914d90d5fee727d61d76905334becflorian               mkU32(0xFFFFFFFF),
767299dd03e04a6914d90d5fee727d61d76905334becflorian               mkU32(1)))
76730e9a0f551e190b475150dcd6bc4500033eb05338sewardj       );
76740e9a0f551e190b475150dcd6bc4500033eb05338sewardj
76750e9a0f551e190b475150dcd6bc4500033eb05338sewardj   /* Set the ID flag */
76760e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put(
76770e9a0f551e190b475150dcd6bc4500033eb05338sewardj            OFFB_IDFLAG,
767899dd03e04a6914d90d5fee727d61d76905334becflorian            IRExpr_ITE(
7679009230b9758291b594e60d7c0243a73d53e81854sewardj               unop(Iop_32to1,
76800e9a0f551e190b475150dcd6bc4500033eb05338sewardj                    binop(Iop_And32,
76810e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
76820e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          mkU32(1))),
768399dd03e04a6914d90d5fee727d61d76905334becflorian               mkU32(1),
768499dd03e04a6914d90d5fee727d61d76905334becflorian               mkU32(0)))
76850e9a0f551e190b475150dcd6bc4500033eb05338sewardj       );
76860e9a0f551e190b475150dcd6bc4500033eb05338sewardj
76870e9a0f551e190b475150dcd6bc4500033eb05338sewardj   /* And set the AC flag.  If setting it 1 to, possibly emit an
76880e9a0f551e190b475150dcd6bc4500033eb05338sewardj      emulation warning. */
76890e9a0f551e190b475150dcd6bc4500033eb05338sewardj   stmt( IRStmt_Put(
76900e9a0f551e190b475150dcd6bc4500033eb05338sewardj            OFFB_ACFLAG,
769199dd03e04a6914d90d5fee727d61d76905334becflorian            IRExpr_ITE(
7692009230b9758291b594e60d7c0243a73d53e81854sewardj               unop(Iop_32to1,
76930e9a0f551e190b475150dcd6bc4500033eb05338sewardj                    binop(Iop_And32,
76940e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          binop(Iop_Shr32, mkexpr(t1), mkU8(18)),
76950e9a0f551e190b475150dcd6bc4500033eb05338sewardj                          mkU32(1))),
769699dd03e04a6914d90d5fee727d61d76905334becflorian               mkU32(1),
769799dd03e04a6914d90d5fee727d61d76905334becflorian               mkU32(0)))
76980e9a0f551e190b475150dcd6bc4500033eb05338sewardj       );
76990e9a0f551e190b475150dcd6bc4500033eb05338sewardj
77000e9a0f551e190b475150dcd6bc4500033eb05338sewardj   if (emit_AC_emwarn) {
77010e9a0f551e190b475150dcd6bc4500033eb05338sewardj      put_emwarn( mkU32(EmWarn_X86_acFlag) );
77020e9a0f551e190b475150dcd6bc4500033eb05338sewardj      stmt(
77030e9a0f551e190b475150dcd6bc4500033eb05338sewardj         IRStmt_Exit(
77040e9a0f551e190b475150dcd6bc4500033eb05338sewardj            binop( Iop_CmpNE32,
77050e9a0f551e190b475150dcd6bc4500033eb05338sewardj                   binop(Iop_And32, mkexpr(t1), mkU32(1<<18)),
77060e9a0f551e190b475150dcd6bc4500033eb05338sewardj                   mkU32(0) ),
77070e9a0f551e190b475150dcd6bc4500033eb05338sewardj            Ijk_EmWarn,
7708c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            IRConst_U32( next_insn_EIP ),
7709c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            OFFB_EIP
77100e9a0f551e190b475150dcd6bc4500033eb05338sewardj         )
77110e9a0f551e190b475150dcd6bc4500033eb05338sewardj      );
77120e9a0f551e190b475150dcd6bc4500033eb05338sewardj   }
77130e9a0f551e190b475150dcd6bc4500033eb05338sewardj}
77140e9a0f551e190b475150dcd6bc4500033eb05338sewardj
77154cb918d355cef4e7640d374346852db4556f3524sewardj
7716150c9cddb753ad4dc38f43484144523174d38b02sewardj/* Helper for the SSSE3 (not SSE3) PMULHRSW insns.  Given two 64-bit
7717150c9cddb753ad4dc38f43484144523174d38b02sewardj   values (aa,bb), computes, for each of the 4 16-bit lanes:
7718150c9cddb753ad4dc38f43484144523174d38b02sewardj
7719150c9cddb753ad4dc38f43484144523174d38b02sewardj   (((aa_lane *s32 bb_lane) >>u 14) + 1) >>u 1
7720150c9cddb753ad4dc38f43484144523174d38b02sewardj*/
7721150c9cddb753ad4dc38f43484144523174d38b02sewardjstatic IRExpr* dis_PMULHRSW_helper ( IRExpr* aax, IRExpr* bbx )
7722150c9cddb753ad4dc38f43484144523174d38b02sewardj{
7723150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp aa      = newTemp(Ity_I64);
7724150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp bb      = newTemp(Ity_I64);
7725150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp aahi32s = newTemp(Ity_I64);
7726150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp aalo32s = newTemp(Ity_I64);
7727150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp bbhi32s = newTemp(Ity_I64);
7728150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp bblo32s = newTemp(Ity_I64);
7729150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp rHi     = newTemp(Ity_I64);
7730150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp rLo     = newTemp(Ity_I64);
7731150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp one32x2 = newTemp(Ity_I64);
7732150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign(aa, aax);
7733150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign(bb, bbx);
7734150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( aahi32s,
7735150c9cddb753ad4dc38f43484144523174d38b02sewardj           binop(Iop_SarN32x2,
7736150c9cddb753ad4dc38f43484144523174d38b02sewardj                 binop(Iop_InterleaveHI16x4, mkexpr(aa), mkexpr(aa)),
7737150c9cddb753ad4dc38f43484144523174d38b02sewardj                 mkU8(16) ));
7738150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( aalo32s,
7739150c9cddb753ad4dc38f43484144523174d38b02sewardj           binop(Iop_SarN32x2,
7740150c9cddb753ad4dc38f43484144523174d38b02sewardj                 binop(Iop_InterleaveLO16x4, mkexpr(aa), mkexpr(aa)),
7741150c9cddb753ad4dc38f43484144523174d38b02sewardj                 mkU8(16) ));
7742150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( bbhi32s,
7743150c9cddb753ad4dc38f43484144523174d38b02sewardj           binop(Iop_SarN32x2,
7744150c9cddb753ad4dc38f43484144523174d38b02sewardj                 binop(Iop_InterleaveHI16x4, mkexpr(bb), mkexpr(bb)),
7745150c9cddb753ad4dc38f43484144523174d38b02sewardj                 mkU8(16) ));
7746150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( bblo32s,
7747150c9cddb753ad4dc38f43484144523174d38b02sewardj           binop(Iop_SarN32x2,
7748150c9cddb753ad4dc38f43484144523174d38b02sewardj                 binop(Iop_InterleaveLO16x4, mkexpr(bb), mkexpr(bb)),
7749150c9cddb753ad4dc38f43484144523174d38b02sewardj                 mkU8(16) ));
7750150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign(one32x2, mkU64( (1ULL << 32) + 1 ));
7751150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign(
7752150c9cddb753ad4dc38f43484144523174d38b02sewardj      rHi,
7753150c9cddb753ad4dc38f43484144523174d38b02sewardj      binop(
7754150c9cddb753ad4dc38f43484144523174d38b02sewardj         Iop_ShrN32x2,
7755150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(
7756150c9cddb753ad4dc38f43484144523174d38b02sewardj            Iop_Add32x2,
7757150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(
7758150c9cddb753ad4dc38f43484144523174d38b02sewardj               Iop_ShrN32x2,
7759150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_Mul32x2, mkexpr(aahi32s), mkexpr(bbhi32s)),
7760150c9cddb753ad4dc38f43484144523174d38b02sewardj               mkU8(14)
7761150c9cddb753ad4dc38f43484144523174d38b02sewardj            ),
7762150c9cddb753ad4dc38f43484144523174d38b02sewardj            mkexpr(one32x2)
7763150c9cddb753ad4dc38f43484144523174d38b02sewardj         ),
7764150c9cddb753ad4dc38f43484144523174d38b02sewardj         mkU8(1)
7765150c9cddb753ad4dc38f43484144523174d38b02sewardj      )
7766150c9cddb753ad4dc38f43484144523174d38b02sewardj   );
7767150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign(
7768150c9cddb753ad4dc38f43484144523174d38b02sewardj      rLo,
7769150c9cddb753ad4dc38f43484144523174d38b02sewardj      binop(
7770150c9cddb753ad4dc38f43484144523174d38b02sewardj         Iop_ShrN32x2,
7771150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(
7772150c9cddb753ad4dc38f43484144523174d38b02sewardj            Iop_Add32x2,
7773150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(
7774150c9cddb753ad4dc38f43484144523174d38b02sewardj               Iop_ShrN32x2,
7775150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_Mul32x2, mkexpr(aalo32s), mkexpr(bblo32s)),
7776150c9cddb753ad4dc38f43484144523174d38b02sewardj               mkU8(14)
7777150c9cddb753ad4dc38f43484144523174d38b02sewardj            ),
7778150c9cddb753ad4dc38f43484144523174d38b02sewardj            mkexpr(one32x2)
7779150c9cddb753ad4dc38f43484144523174d38b02sewardj         ),
7780150c9cddb753ad4dc38f43484144523174d38b02sewardj         mkU8(1)
7781150c9cddb753ad4dc38f43484144523174d38b02sewardj      )
7782150c9cddb753ad4dc38f43484144523174d38b02sewardj   );
7783150c9cddb753ad4dc38f43484144523174d38b02sewardj   return
7784150c9cddb753ad4dc38f43484144523174d38b02sewardj      binop(Iop_CatEvenLanes16x4, mkexpr(rHi), mkexpr(rLo));
7785150c9cddb753ad4dc38f43484144523174d38b02sewardj}
7786150c9cddb753ad4dc38f43484144523174d38b02sewardj
7787150c9cddb753ad4dc38f43484144523174d38b02sewardj/* Helper for the SSSE3 (not SSE3) PSIGN{B,W,D} insns.  Given two 64-bit
7788150c9cddb753ad4dc38f43484144523174d38b02sewardj   values (aa,bb), computes, for each lane:
7789150c9cddb753ad4dc38f43484144523174d38b02sewardj
7790150c9cddb753ad4dc38f43484144523174d38b02sewardj          if aa_lane < 0 then - bb_lane
7791150c9cddb753ad4dc38f43484144523174d38b02sewardj     else if aa_lane > 0 then bb_lane
7792150c9cddb753ad4dc38f43484144523174d38b02sewardj     else 0
7793150c9cddb753ad4dc38f43484144523174d38b02sewardj*/
7794150c9cddb753ad4dc38f43484144523174d38b02sewardjstatic IRExpr* dis_PSIGN_helper ( IRExpr* aax, IRExpr* bbx, Int laneszB )
7795150c9cddb753ad4dc38f43484144523174d38b02sewardj{
7796150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp aa       = newTemp(Ity_I64);
7797150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp bb       = newTemp(Ity_I64);
7798150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp zero     = newTemp(Ity_I64);
7799150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp bbNeg    = newTemp(Ity_I64);
7800150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp negMask  = newTemp(Ity_I64);
7801150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp posMask  = newTemp(Ity_I64);
7802150c9cddb753ad4dc38f43484144523174d38b02sewardj   IROp   opSub    = Iop_INVALID;
7803150c9cddb753ad4dc38f43484144523174d38b02sewardj   IROp   opCmpGTS = Iop_INVALID;
7804150c9cddb753ad4dc38f43484144523174d38b02sewardj
7805150c9cddb753ad4dc38f43484144523174d38b02sewardj   switch (laneszB) {
7806150c9cddb753ad4dc38f43484144523174d38b02sewardj      case 1: opSub = Iop_Sub8x8;  opCmpGTS = Iop_CmpGT8Sx8;  break;
7807150c9cddb753ad4dc38f43484144523174d38b02sewardj      case 2: opSub = Iop_Sub16x4; opCmpGTS = Iop_CmpGT16Sx4; break;
7808150c9cddb753ad4dc38f43484144523174d38b02sewardj      case 4: opSub = Iop_Sub32x2; opCmpGTS = Iop_CmpGT32Sx2; break;
7809150c9cddb753ad4dc38f43484144523174d38b02sewardj      default: vassert(0);
7810150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
7811150c9cddb753ad4dc38f43484144523174d38b02sewardj
7812150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( aa,      aax );
7813150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( bb,      bbx );
7814150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( zero,    mkU64(0) );
7815150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( bbNeg,   binop(opSub,    mkexpr(zero), mkexpr(bb)) );
7816150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( negMask, binop(opCmpGTS, mkexpr(zero), mkexpr(aa)) );
7817150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( posMask, binop(opCmpGTS, mkexpr(aa),   mkexpr(zero)) );
7818150c9cddb753ad4dc38f43484144523174d38b02sewardj
7819150c9cddb753ad4dc38f43484144523174d38b02sewardj   return
7820150c9cddb753ad4dc38f43484144523174d38b02sewardj      binop(Iop_Or64,
7821150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64, mkexpr(bb),    mkexpr(posMask)),
7822150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64, mkexpr(bbNeg), mkexpr(negMask)) );
7823150c9cddb753ad4dc38f43484144523174d38b02sewardj
7824150c9cddb753ad4dc38f43484144523174d38b02sewardj}
7825150c9cddb753ad4dc38f43484144523174d38b02sewardj
7826150c9cddb753ad4dc38f43484144523174d38b02sewardj/* Helper for the SSSE3 (not SSE3) PABS{B,W,D} insns.  Given a 64-bit
7827150c9cddb753ad4dc38f43484144523174d38b02sewardj   value aa, computes, for each lane
7828150c9cddb753ad4dc38f43484144523174d38b02sewardj
7829150c9cddb753ad4dc38f43484144523174d38b02sewardj   if aa < 0 then -aa else aa
7830150c9cddb753ad4dc38f43484144523174d38b02sewardj
7831150c9cddb753ad4dc38f43484144523174d38b02sewardj   Note that the result is interpreted as unsigned, so that the
7832150c9cddb753ad4dc38f43484144523174d38b02sewardj   absolute value of the most negative signed input can be
7833150c9cddb753ad4dc38f43484144523174d38b02sewardj   represented.
7834150c9cddb753ad4dc38f43484144523174d38b02sewardj*/
7835150c9cddb753ad4dc38f43484144523174d38b02sewardjstatic IRExpr* dis_PABS_helper ( IRExpr* aax, Int laneszB )
7836150c9cddb753ad4dc38f43484144523174d38b02sewardj{
7837150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp aa      = newTemp(Ity_I64);
7838150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp zero    = newTemp(Ity_I64);
7839150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp aaNeg   = newTemp(Ity_I64);
7840150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp negMask = newTemp(Ity_I64);
7841150c9cddb753ad4dc38f43484144523174d38b02sewardj   IRTemp posMask = newTemp(Ity_I64);
7842150c9cddb753ad4dc38f43484144523174d38b02sewardj   IROp   opSub   = Iop_INVALID;
7843150c9cddb753ad4dc38f43484144523174d38b02sewardj   IROp   opSarN  = Iop_INVALID;
7844150c9cddb753ad4dc38f43484144523174d38b02sewardj
7845150c9cddb753ad4dc38f43484144523174d38b02sewardj   switch (laneszB) {
7846150c9cddb753ad4dc38f43484144523174d38b02sewardj      case 1: opSub = Iop_Sub8x8;  opSarN = Iop_SarN8x8;  break;
7847150c9cddb753ad4dc38f43484144523174d38b02sewardj      case 2: opSub = Iop_Sub16x4; opSarN = Iop_SarN16x4; break;
7848150c9cddb753ad4dc38f43484144523174d38b02sewardj      case 4: opSub = Iop_Sub32x2; opSarN = Iop_SarN32x2; break;
7849150c9cddb753ad4dc38f43484144523174d38b02sewardj      default: vassert(0);
7850150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
7851150c9cddb753ad4dc38f43484144523174d38b02sewardj
7852150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( aa,      aax );
7853150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( negMask, binop(opSarN, mkexpr(aa), mkU8(8*laneszB-1)) );
7854150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( posMask, unop(Iop_Not64, mkexpr(negMask)) );
7855150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( zero,    mkU64(0) );
7856150c9cddb753ad4dc38f43484144523174d38b02sewardj   assign( aaNeg,   binop(opSub, mkexpr(zero), mkexpr(aa)) );
7857150c9cddb753ad4dc38f43484144523174d38b02sewardj   return
7858150c9cddb753ad4dc38f43484144523174d38b02sewardj      binop(Iop_Or64,
7859150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64, mkexpr(aa),    mkexpr(posMask)),
7860150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64, mkexpr(aaNeg), mkexpr(negMask)) );
7861150c9cddb753ad4dc38f43484144523174d38b02sewardj}
7862150c9cddb753ad4dc38f43484144523174d38b02sewardj
7863150c9cddb753ad4dc38f43484144523174d38b02sewardjstatic IRExpr* dis_PALIGNR_XMM_helper ( IRTemp hi64,
7864150c9cddb753ad4dc38f43484144523174d38b02sewardj                                        IRTemp lo64, Int byteShift )
7865150c9cddb753ad4dc38f43484144523174d38b02sewardj{
7866150c9cddb753ad4dc38f43484144523174d38b02sewardj   vassert(byteShift >= 1 && byteShift <= 7);
7867150c9cddb753ad4dc38f43484144523174d38b02sewardj   return
7868150c9cddb753ad4dc38f43484144523174d38b02sewardj      binop(Iop_Or64,
7869150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_Shl64, mkexpr(hi64), mkU8(8*(8-byteShift))),
7870150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_Shr64, mkexpr(lo64), mkU8(8*byteShift))
7871150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
7872150c9cddb753ad4dc38f43484144523174d38b02sewardj}
7873150c9cddb753ad4dc38f43484144523174d38b02sewardj
7874150c9cddb753ad4dc38f43484144523174d38b02sewardj/* Generate a SIGSEGV followed by a restart of the current instruction
7875150c9cddb753ad4dc38f43484144523174d38b02sewardj   if effective_addr is not 16-aligned.  This is required behaviour
7876150c9cddb753ad4dc38f43484144523174d38b02sewardj   for some SSE3 instructions and all 128-bit SSSE3 instructions.
7877150c9cddb753ad4dc38f43484144523174d38b02sewardj   This assumes that guest_RIP_curr_instr is set correctly! */
7878150c9cddb753ad4dc38f43484144523174d38b02sewardjstatic void gen_SEGV_if_not_16_aligned ( IRTemp effective_addr )
7879150c9cddb753ad4dc38f43484144523174d38b02sewardj{
7880150c9cddb753ad4dc38f43484144523174d38b02sewardj   stmt(
7881150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRStmt_Exit(
7882150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_CmpNE32,
7883150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_And32,mkexpr(effective_addr),mkU32(0xF)),
7884150c9cddb753ad4dc38f43484144523174d38b02sewardj               mkU32(0)),
7885150c9cddb753ad4dc38f43484144523174d38b02sewardj         Ijk_SigSEGV,
7886c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         IRConst_U32(guest_EIP_curr_instr),
7887c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         OFFB_EIP
7888150c9cddb753ad4dc38f43484144523174d38b02sewardj      )
7889150c9cddb753ad4dc38f43484144523174d38b02sewardj   );
7890150c9cddb753ad4dc38f43484144523174d38b02sewardj}
7891150c9cddb753ad4dc38f43484144523174d38b02sewardj
7892150c9cddb753ad4dc38f43484144523174d38b02sewardj
7893c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj/* Helper for deciding whether a given insn (starting at the opcode
7894c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   byte) may validly be used with a LOCK prefix.  The following insns
7895c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   may be used with LOCK when their destination operand is in memory.
7896e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   AFAICS this is exactly the same for both 32-bit and 64-bit mode.
7897c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7898e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   ADD        80 /0,  81 /0,  82 /0,  83 /0,  00,  01
7899e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   OR         80 /1,  81 /1,  82 /x,  83 /1,  08,  09
7900e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   ADC        80 /2,  81 /2,  82 /2,  83 /2,  10,  11
7901e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   SBB        81 /3,  81 /3,  82 /x,  83 /3,  18,  19
7902e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   AND        80 /4,  81 /4,  82 /x,  83 /4,  20,  21
7903e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   SUB        80 /5,  81 /5,  82 /x,  83 /5,  28,  29
7904e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   XOR        80 /6,  81 /6,  82 /x,  83 /6,  30,  31
7905c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7906c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   DEC        FE /1,  FF /1
7907c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   INC        FE /0,  FF /0
7908c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7909c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   NEG        F6 /3,  F7 /3
7910c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   NOT        F6 /2,  F7 /2
7911c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7912e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   XCHG       86, 87
7913c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7914c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   BTC        0F BB,  0F BA /7
7915c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   BTR        0F B3,  0F BA /6
7916c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   BTS        0F AB,  0F BA /5
7917c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7918c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   CMPXCHG    0F B0,  0F B1
7919c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   CMPXCHG8B  0F C7 /1
7920c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7921c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   XADD       0F C0,  0F C1
7922e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7923e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   ------------------------------
7924e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7925e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   80 /0  =  addb $imm8,  rm8
7926e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   81 /0  =  addl $imm32, rm32  and  addw $imm16, rm16
7927e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   82 /0  =  addb $imm8,  rm8
7928e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   83 /0  =  addl $simm8, rm32  and  addw $simm8, rm16
7929e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7930e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   00     =  addb r8,  rm8
7931e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   01     =  addl r32, rm32  and  addw r16, rm16
7932e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7933e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   Same for ADD OR ADC SBB AND SUB XOR
7934e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7935e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   FE /1  = dec rm8
7936e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   FF /1  = dec rm32  and  dec rm16
7937e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7938e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   FE /0  = inc rm8
7939e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   FF /0  = inc rm32  and  inc rm16
7940e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7941e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   F6 /3  = neg rm8
7942e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   F7 /3  = neg rm32  and  neg rm16
7943e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7944e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   F6 /2  = not rm8
7945e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   F7 /2  = not rm32  and  not rm16
7946e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7947e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   0F BB     = btcw r16, rm16    and  btcl r32, rm32
7948e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   OF BA /7  = btcw $imm8, rm16  and  btcw $imm8, rm32
7949e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7950e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   Same for BTS, BTR
7951c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj*/
79528462d113e3efeacceb304222dada8d85f748295aflorianstatic Bool can_be_used_with_LOCK_prefix ( const UChar* opc )
7953c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj{
7954c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   switch (opc[0]) {
7955e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      case 0x00: case 0x01: case 0x08: case 0x09:
7956e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      case 0x10: case 0x11: case 0x18: case 0x19:
7957e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      case 0x20: case 0x21: case 0x28: case 0x29:
7958e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      case 0x30: case 0x31:
7959e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (!epartIsReg(opc[1]))
7960e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            return True;
7961e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         break;
7962e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
7963e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      case 0x80: case 0x81: case 0x82: case 0x83:
7964e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 6
7965e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj             && !epartIsReg(opc[1]))
7966c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            return True;
7967c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         break;
7968c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7969c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      case 0xFE: case 0xFF:
7970e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 1
7971e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj             && !epartIsReg(opc[1]))
7972c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            return True;
7973c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         break;
7974c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7975c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      case 0xF6: case 0xF7:
7976e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (gregOfRM(opc[1]) >= 2 && gregOfRM(opc[1]) <= 3
7977e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj             && !epartIsReg(opc[1]))
7978c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            return True;
7979c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         break;
7980c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7981c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      case 0x86: case 0x87:
7982e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (!epartIsReg(opc[1]))
7983e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            return True;
7984e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         break;
7985c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
7986c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      case 0x0F: {
7987c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         switch (opc[1]) {
7988c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            case 0xBB: case 0xB3: case 0xAB:
7989e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (!epartIsReg(opc[2]))
7990e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  return True;
7991e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               break;
7992c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            case 0xBA:
7993e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (gregOfRM(opc[2]) >= 5 && gregOfRM(opc[2]) <= 7
7994e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                   && !epartIsReg(opc[2]))
7995c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj                  return True;
7996c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               break;
7997c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            case 0xB0: case 0xB1:
7998e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (!epartIsReg(opc[2]))
7999e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  return True;
8000e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               break;
8001c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            case 0xC7:
8002e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (gregOfRM(opc[2]) == 1 && !epartIsReg(opc[2]) )
8003c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj                  return True;
8004c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               break;
8005c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            case 0xC0: case 0xC1:
8006e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               if (!epartIsReg(opc[2]))
8007e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  return True;
8008e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               break;
8009c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            default:
8010c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               break;
8011c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         } /* switch (opc[1]) */
8012c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         break;
8013c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      }
8014c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8015c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      default:
8016c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         break;
8017c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   } /* switch (opc[0]) */
8018c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8019c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   return False;
8020c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj}
8021c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8022021f6b420c3ce127091cdf3e1facbfabbe92100fsewardjstatic IRTemp math_BSWAP ( IRTemp t1, IRType ty )
8023021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj{
8024021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   IRTemp t2 = newTemp(ty);
8025021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   if (ty == Ity_I32) {
8026021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      assign( t2,
8027021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         binop(
8028021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj            Iop_Or32,
8029021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj            binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
8030021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj            binop(
8031021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj               Iop_Or32,
8032021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj               binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
8033021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                                mkU32(0x00FF0000)),
8034021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj               binop(Iop_Or32,
8035021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                     binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
8036021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                                      mkU32(0x0000FF00)),
8037021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                     binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
8038021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                                      mkU32(0x000000FF) )
8039021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj            )))
8040021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      );
8041021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      return t2;
8042021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   }
8043021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   if (ty == Ity_I16) {
8044021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      assign(t2,
8045021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj             binop(Iop_Or16,
8046021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                   binop(Iop_Shl16, mkexpr(t1), mkU8(8)),
8047021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj                   binop(Iop_Shr16, mkexpr(t1), mkU8(8)) ));
8048021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      return t2;
8049021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   }
8050021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   vassert(0);
8051021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   /*NOTREACHED*/
8052021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   return IRTemp_INVALID;
8053021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj}
8054c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8055c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*------------------------------------------------------------*/
8056ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj/*--- Disassemble a single instruction                     ---*/
8057c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*------------------------------------------------------------*/
8058c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8059e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj/* Disassemble a single instruction into IR.  The instruction is
8060e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   located in host memory at &guest_code[delta].  *expect_CAS is set
8061e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   to True if the resulting IR is expected to contain an IRCAS
8062e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   statement, and False if it's not expected to.  This makes it
8063e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   possible for the caller of disInstr_X86_WRK to check that
8064e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   LOCK-prefixed instructions are at least plausibly translated, in
8065e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   that it becomes possible to check that a (validly) LOCK-prefixed
8066e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   instruction generates a translation containing an IRCAS, and
8067e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   instructions without LOCK prefixes don't generate translations
8068e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   containing an IRCAS.
8069e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj*/
80709e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardjstatic
8071e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardjDisResult disInstr_X86_WRK (
8072e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj             /*OUT*/Bool* expect_CAS,
8073beac530a718fcc646bc61fe60a86f599df54e1d7florian             Bool         (*resteerOkFn) ( /*opaque*/void*, Addr ),
8074984d9b164dd17f07e603c41fe1e506e641e57d18sewardj             Bool         resteerCisOk,
8075c716aea1cafe66ee431dc7d6909c98f18788a028sewardj             void*        callback_opaque,
80769e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj             Long         delta64,
8077cacba8e675988fbf21b08feea1f317a9c896c053florian             const VexArchInfo* archinfo,
8078cacba8e675988fbf21b08feea1f317a9c896c053florian             const VexAbiInfo*  vbi,
8079442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj             Bool         sigill_diag
80809e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj          )
8081c9a6570e86f4252f8a486b4df48de8710d357a4asewardj{
8082ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj   IRType    ty;
8083b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   IRTemp    addr, t0, t1, t2, t3, t4, t5, t6;
8084ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj   Int       alen;
8085c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   UChar     opc, modrm, abyte, pre;
8086ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj   UInt      d32;
8087c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   HChar     dis_buf[50];
8088c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   Int       am_sz, d_sz, n_prefixes;
80899e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   DisResult dres;
80908462d113e3efeacceb304222dada8d85f748295aflorian   const UChar* insn; /* used in SSE decoders */
8091ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj
80929e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   /* The running delta */
80939e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   Int delta = (Int)delta64;
80949e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
8095c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* Holds eip at the start of the insn, so that we can print
8096c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      consistent error messages for unimplemented insns. */
80979e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   Int delta_start = delta;
8098c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8099c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* sz denotes the nominal data-op size of the insn; we change it to
8100c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      2 if an 0x66 prefix is seen */
8101c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   Int sz = 4;
8102c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8103c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* sorb holds the segment-override-prefix byte, if any.  Zero if no
8104c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
8105c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      indicating the prefix.  */
8106c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   UChar sorb = 0;
8107c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8108c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   /* Gets set to True if a LOCK prefix is seen. */
8109c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   Bool pfx_lock = False;
8110c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
81119e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   /* Set result defaults. */
8112c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres.whatNext    = Dis_Continue;
8113c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres.len         = 0;
8114c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres.continueAt  = 0;
8115c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres.jk_StopHere = Ijk_INVALID;
8116ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj
8117e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   *expect_CAS = False;
8118e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
8119b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
8120c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8121e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   vassert(guest_EIP_bbstart + delta == guest_EIP_curr_instr);
81229e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   DIP("\t0x%x:  ", guest_EIP_bbstart+delta);
81239e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
8124ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj   /* Spot "Special" instructions (see comment at top of file). */
8125750f407b6be1aac303964a219acf0a6de8b8c4dasewardj   {
81268462d113e3efeacceb304222dada8d85f748295aflorian      const UChar* code = guest_code + delta;
8127ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj      /* Spot the 12-byte preamble:
8128ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         C1C703   roll $3,  %edi
8129ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         C1C70D   roll $13, %edi
8130ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         C1C71D   roll $29, %edi
8131ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         C1C713   roll $19, %edi
8132750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      */
8133ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj      if (code[ 0] == 0xC1 && code[ 1] == 0xC7 && code[ 2] == 0x03 &&
8134ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj          code[ 3] == 0xC1 && code[ 4] == 0xC7 && code[ 5] == 0x0D &&
8135ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj          code[ 6] == 0xC1 && code[ 7] == 0xC7 && code[ 8] == 0x1D &&
8136ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj          code[ 9] == 0xC1 && code[10] == 0xC7 && code[11] == 0x13) {
8137ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         /* Got a "Special" instruction preamble.  Which one is it? */
8138ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         if (code[12] == 0x87 && code[13] == 0xDB /* xchgl %ebx,%ebx */) {
8139ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            /* %EDX = client_request ( %EAX ) */
8140ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            DIP("%%edx = client_request ( %%eax )\n");
8141ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            delta += 14;
8142c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_lit(&dres, Ijk_ClientReq, guest_EIP_bbstart+delta);
8143c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres.whatNext == Dis_StopHere);
8144ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            goto decode_success;
8145ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         }
8146ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         else
8147ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         if (code[12] == 0x87 && code[13] == 0xC9 /* xchgl %ecx,%ecx */) {
8148ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            /* %EAX = guest_NRADDR */
8149ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            DIP("%%eax = guest_NRADDR\n");
8150ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            delta += 14;
8151ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            putIReg(4, R_EAX, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
8152ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            goto decode_success;
8153ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         }
8154ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         else
8155ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         if (code[12] == 0x87 && code[13] == 0xD2 /* xchgl %edx,%edx */) {
8156ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            /* call-noredir *%EAX */
8157ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            DIP("call-noredir *%%eax\n");
8158ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            delta += 14;
8159ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            t1 = newTemp(Ity_I32);
8160ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            assign(t1, getIReg(4,R_EAX));
8161ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            t2 = newTemp(Ity_I32);
8162ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
8163ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            putIReg(4, R_ESP, mkexpr(t2));
8164ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta));
8165c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_treg(&dres, Ijk_NoRedir, t1);
8166c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres.whatNext == Dis_StopHere);
8167ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj            goto decode_success;
8168ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         }
81692245ce9e834193d49261b8a433b4a0bd128c878eflorian         else
81702245ce9e834193d49261b8a433b4a0bd128c878eflorian         if (code[12] == 0x87 && code[13] == 0xFF /* xchgl %edi,%edi */) {
81712245ce9e834193d49261b8a433b4a0bd128c878eflorian            /* IR injection */
81722245ce9e834193d49261b8a433b4a0bd128c878eflorian            DIP("IR injection\n");
81732245ce9e834193d49261b8a433b4a0bd128c878eflorian            vex_inject_ir(irsb, Iend_LE);
81742245ce9e834193d49261b8a433b4a0bd128c878eflorian
81752245ce9e834193d49261b8a433b4a0bd128c878eflorian            // Invalidate the current insn. The reason is that the IRop we're
81762245ce9e834193d49261b8a433b4a0bd128c878eflorian            // injecting here can change. In which case the translation has to
81772245ce9e834193d49261b8a433b4a0bd128c878eflorian            // be redone. For ease of handling, we simply invalidate all the
81782245ce9e834193d49261b8a433b4a0bd128c878eflorian            // time.
817905f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj            stmt(IRStmt_Put(OFFB_CMSTART, mkU32(guest_EIP_curr_instr)));
818005f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj            stmt(IRStmt_Put(OFFB_CMLEN,   mkU32(14)));
81812245ce9e834193d49261b8a433b4a0bd128c878eflorian
81822245ce9e834193d49261b8a433b4a0bd128c878eflorian            delta += 14;
81832245ce9e834193d49261b8a433b4a0bd128c878eflorian
81842245ce9e834193d49261b8a433b4a0bd128c878eflorian            stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_bbstart + delta) ) );
81852245ce9e834193d49261b8a433b4a0bd128c878eflorian            dres.whatNext    = Dis_StopHere;
818605f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj            dres.jk_StopHere = Ijk_InvalICache;
81872245ce9e834193d49261b8a433b4a0bd128c878eflorian            goto decode_success;
81882245ce9e834193d49261b8a433b4a0bd128c878eflorian         }
8189ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         /* We don't know what it is. */
8190ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         goto decode_failure;
8191ce02aa77bc02dbe225a068df0fb6b31faddedcdfsewardj         /*NOTREACHED*/
8192750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      }
8193750f407b6be1aac303964a219acf0a6de8b8c4dasewardj   }
8194c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8195c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   /* Handle a couple of weird-ass NOPs that have been observed in the
8196c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      wild. */
8197c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   {
81988462d113e3efeacceb304222dada8d85f748295aflorian      const UChar* code = guest_code + delta;
8199c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      /* Sun's JVM 1.5.0 uses the following as a NOP:
8200c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         26 2E 64 65 90  %es:%cs:%fs:%gs:nop */
8201c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      if (code[0] == 0x26 && code[1] == 0x2E && code[2] == 0x64
8202c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj          && code[3] == 0x65 && code[4] == 0x90) {
8203c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         DIP("%%es:%%cs:%%fs:%%gs:nop\n");
8204c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         delta += 5;
8205c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         goto decode_success;
8206bb3f52db829c572ec04002392e8a5056b63affb3sewardj      }
8207deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj      /* Don't barf on recent binutils padding,
8208deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         all variants of which are: nopw %cs:0x0(%eax,%eax,1)
8209deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         66 2e 0f 1f 84 00 00 00 00 00
8210deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         66 66 2e 0f 1f 84 00 00 00 00 00
8211deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         66 66 66 2e 0f 1f 84 00 00 00 00 00
8212deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8213deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8214deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         66 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8215deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj      */
8216deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj      if (code[0] == 0x66) {
8217deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         Int data16_cnt;
8218deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         for (data16_cnt = 1; data16_cnt < 6; data16_cnt++)
8219deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj            if (code[data16_cnt] != 0x66)
8220deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj               break;
8221deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         if (code[data16_cnt] == 0x2E && code[data16_cnt + 1] == 0x0F
8222deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj             && code[data16_cnt + 2] == 0x1F && code[data16_cnt + 3] == 0x84
8223deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj             && code[data16_cnt + 4] == 0x00 && code[data16_cnt + 5] == 0x00
8224deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj             && code[data16_cnt + 6] == 0x00 && code[data16_cnt + 7] == 0x00
8225deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj             && code[data16_cnt + 8] == 0x00 ) {
8226deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj            DIP("nopw %%cs:0x0(%%eax,%%eax,1)\n");
8227deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj            delta += 9 + data16_cnt;
8228deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj            goto decode_success;
8229deceef857cde2b2f678d70dca42886dbe7df7ee3sewardj         }
8230ce4a282154b918641db59c83541d9d573a761decsewardj      }
8231c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   }
8232bb3f52db829c572ec04002392e8a5056b63affb3sewardj
8233c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   /* Normal instruction handling starts here. */
8234c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8235c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   /* Deal with some but not all prefixes:
8236c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         66(oso)
8237c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         F0(lock)
8238c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         2E(cs:) 3E(ds:) 26(es:) 64(fs:) 65(gs:) 36(ss:)
8239c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      Not dealt with (left in place):
8240c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         F2 F3
8241c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   */
8242c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   n_prefixes = 0;
8243c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   while (True) {
8244c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      if (n_prefixes > 7) goto decode_failure;
8245c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      pre = getUChar(delta);
8246c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      switch (pre) {
8247c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0x66:
8248c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            sz = 2;
8249c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            break;
8250c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0xF0:
8251c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            pfx_lock = True;
8252e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            *expect_CAS = True;
8253c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            break;
8254c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0x3E: /* %DS: */
8255c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0x26: /* %ES: */
8256c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0x64: /* %FS: */
8257c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0x65: /* %GS: */
8258c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            if (sorb != 0)
8259c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               goto decode_failure; /* only one seg override allowed */
8260c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            sorb = pre;
8261c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            break;
8262c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0x2E: { /* %CS: */
8263c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            /* 2E prefix on a conditional branch instruction is a
8264c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               branch-prediction hint, which can safely be ignored.  */
8265c9a6570e86f4252f8a486b4df48de8710d357a4asewardj            UChar op1 = getIByte(delta+1);
8266c9a6570e86f4252f8a486b4df48de8710d357a4asewardj            UChar op2 = getIByte(delta+2);
8267c9a6570e86f4252f8a486b4df48de8710d357a4asewardj            if ((op1 >= 0x70 && op1 <= 0x7F)
8268c9a6570e86f4252f8a486b4df48de8710d357a4asewardj                || (op1 == 0xE3)
8269c9a6570e86f4252f8a486b4df48de8710d357a4asewardj                || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
82704dfb199ead988f45252befaec1ae849e9c927509sewardj               if (0) vex_printf("vex x86->IR: ignoring branch hint\n");
8271c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            } else {
8272c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               /* All other CS override cases are not handled */
8273c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj               goto decode_failure;
827487f471d72daee180f8f1e19433ba1c164decdee4sewardj            }
8275c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            break;
827687f471d72daee180f8f1e19433ba1c164decdee4sewardj         }
8277c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         case 0x36: /* %SS: */
8278c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            /* SS override cases are not handled */
8279c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            goto decode_failure;
8280c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         default:
8281c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj            goto not_a_prefix;
8282c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      }
8283c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      n_prefixes++;
8284c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      delta++;
8285c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   }
8286c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8287c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   not_a_prefix:
8288c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8289c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   /* Now we should be looking at the primary opcode byte or the
8290c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      leading F2 or F3.  Check that any LOCK prefix is actually
8291c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      allowed. */
8292c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8293c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   if (pfx_lock) {
82948462d113e3efeacceb304222dada8d85f748295aflorian     if (can_be_used_with_LOCK_prefix( &guest_code[delta] )) {
8295c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         DIP("lock ");
8296c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      } else {
8297e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         *expect_CAS = False;
82989c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj         goto decode_failure;
8299c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      }
8300c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   }
8301c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
8302c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj
8303c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   /* ---------------------------------------------------- */
8304c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   /* --- The SSE decoder.                             --- */
8305c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   /* ---------------------------------------------------- */
8306c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
83074cb918d355cef4e7640d374346852db4556f3524sewardj   /* What did I do to deserve SSE ?  Perhaps I was really bad in a
83084cb918d355cef4e7640d374346852db4556f3524sewardj      previous life? */
83094cb918d355cef4e7640d374346852db4556f3524sewardj
83109df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj   /* Note, this doesn't handle SSE2 or SSE3.  That is handled in a
83119df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj      later section, further on. */
83129df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj
83138462d113e3efeacceb304222dada8d85f748295aflorian   insn = &guest_code[delta];
8314a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8315a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   /* Treat fxsave specially.  It should be doable even on an SSE0
8316a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      (Pentium-II class) CPU.  Hence be prepared to handle it on
8317a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      any subarchitecture variant.
8318a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   */
8319a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8320a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
8321a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8322a0e83b06f304527e3e9aec527c344e35e7023d76sewardj       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
83239a036bf85bea7071ee235b8f7010e574ae71c6f0sewardj      IRDirty* d;
8324a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      modrm = getIByte(delta+2);
8325a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      vassert(sz == 4);
8326a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      vassert(!epartIsReg(modrm));
8327a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8328a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8329a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      delta += 2+alen;
8330ec993dea5afed8192e4419856025a18a3b7cb2cbsewardj      gen_SEGV_if_not_16_aligned(addr);
8331a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
833233dd31b1bcc175495b96222fa278062fd6116899sewardj      DIP("fxsave %s\n", dis_buf);
8333a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8334a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      /* Uses dirty helper:
8335a0e83b06f304527e3e9aec527c344e35e7023d76sewardj            void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
83369a036bf85bea7071ee235b8f7010e574ae71c6f0sewardj      d = unsafeIRDirty_0_N (
83379a036bf85bea7071ee235b8f7010e574ae71c6f0sewardj             0/*regparms*/,
83389a036bf85bea7071ee235b8f7010e574ae71c6f0sewardj             "x86g_dirtyhelper_FXSAVE",
83399a036bf85bea7071ee235b8f7010e574ae71c6f0sewardj             &x86g_dirtyhelper_FXSAVE,
83409041956f39c57e265122ed0a71061dea1e554edcflorian             mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
83419a036bf85bea7071ee235b8f7010e574ae71c6f0sewardj          );
8342a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8343a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      /* declare we're writing memory */
8344a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->mFx   = Ifx_Write;
8345a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->mAddr = mkexpr(addr);
8346c9069f2908814843e9a4da00da9c8905440195a6sewardj      d->mSize = 464; /* according to recent Intel docs */
8347a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8348a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      /* declare we're reading guest state */
8349a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->nFxState = 7;
8350c9069f2908814843e9a4da00da9c8905440195a6sewardj      vex_bzero(&d->fxState, sizeof(d->fxState));
8351a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8352a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[0].fx     = Ifx_Read;
8353a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[0].offset = OFFB_FTOP;
8354a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[0].size   = sizeof(UInt);
8355a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8356a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[1].fx     = Ifx_Read;
8357a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[1].offset = OFFB_FPREGS;
8358a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[1].size   = 8 * sizeof(ULong);
8359a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8360a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[2].fx     = Ifx_Read;
8361a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[2].offset = OFFB_FPTAGS;
8362a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[2].size   = 8 * sizeof(UChar);
8363a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8364a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[3].fx     = Ifx_Read;
8365a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[3].offset = OFFB_FPROUND;
8366a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[3].size   = sizeof(UInt);
8367a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8368a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[4].fx     = Ifx_Read;
8369a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[4].offset = OFFB_FC3210;
8370a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[4].size   = sizeof(UInt);
8371a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8372a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[5].fx     = Ifx_Read;
8373a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[5].offset = OFFB_XMM0;
8374a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[5].size   = 8 * sizeof(U128);
8375a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8376a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[6].fx     = Ifx_Read;
8377a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[6].offset = OFFB_SSEROUND;
8378a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      d->fxState[6].size   = sizeof(UInt);
8379a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8380a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8381a0e83b06f304527e3e9aec527c344e35e7023d76sewardj	 images are packed back-to-back.  If not, the value of
8382a0e83b06f304527e3e9aec527c344e35e7023d76sewardj	 d->fxState[5].size is wrong. */
8383a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      vassert(16 == sizeof(U128));
8384a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
83853800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
83863800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      stmt( IRStmt_Dirty(d) );
83873800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
83883800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      goto decode_success;
83893800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj   }
83903800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
83913800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj   /* 0F AE /1 = FXRSTOR m512 -- read x87 and SSE state from memory */
83923800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
83933800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 1) {
83943800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      IRDirty* d;
83953800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      modrm = getIByte(delta+2);
83963800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      vassert(sz == 4);
83973800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      vassert(!epartIsReg(modrm));
83983800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
83993800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
84003800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      delta += 2+alen;
8401ec993dea5afed8192e4419856025a18a3b7cb2cbsewardj      gen_SEGV_if_not_16_aligned(addr);
84023800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84033800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      DIP("fxrstor %s\n", dis_buf);
84043800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84053800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      /* Uses dirty helper:
84066ef84bed9bb3af22060eb1759788034602bbcc88florian            VexEmNote x86g_do_FXRSTOR ( VexGuestX86State*, UInt )
8407ec993dea5afed8192e4419856025a18a3b7cb2cbsewardj         NOTE:
84086ef84bed9bb3af22060eb1759788034602bbcc88florian            the VexEmNote value is simply ignored (unlike for FRSTOR)
8409ec993dea5afed8192e4419856025a18a3b7cb2cbsewardj      */
84103800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d = unsafeIRDirty_0_N (
84113800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj             0/*regparms*/,
84123800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj             "x86g_dirtyhelper_FXRSTOR",
84133800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj             &x86g_dirtyhelper_FXRSTOR,
84149041956f39c57e265122ed0a71061dea1e554edcflorian             mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
84153800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj          );
84163800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84173800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      /* declare we're reading memory */
84183800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->mFx   = Ifx_Read;
84193800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->mAddr = mkexpr(addr);
8420c9069f2908814843e9a4da00da9c8905440195a6sewardj      d->mSize = 464; /* according to recent Intel docs */
84213800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84223800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      /* declare we're writing guest state */
84233800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->nFxState = 7;
8424c9069f2908814843e9a4da00da9c8905440195a6sewardj      vex_bzero(&d->fxState, sizeof(d->fxState));
84253800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84263800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[0].fx     = Ifx_Write;
84273800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[0].offset = OFFB_FTOP;
84283800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[0].size   = sizeof(UInt);
84293800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84303800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[1].fx     = Ifx_Write;
84313800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[1].offset = OFFB_FPREGS;
84323800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[1].size   = 8 * sizeof(ULong);
84333800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84343800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[2].fx     = Ifx_Write;
84353800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[2].offset = OFFB_FPTAGS;
84363800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[2].size   = 8 * sizeof(UChar);
84373800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84383800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[3].fx     = Ifx_Write;
84393800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[3].offset = OFFB_FPROUND;
84403800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[3].size   = sizeof(UInt);
84413800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84423800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[4].fx     = Ifx_Write;
84433800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[4].offset = OFFB_FC3210;
84443800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[4].size   = sizeof(UInt);
84453800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84463800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[5].fx     = Ifx_Write;
84473800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[5].offset = OFFB_XMM0;
84483800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[5].size   = 8 * sizeof(U128);
84493800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84503800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[6].fx     = Ifx_Write;
84513800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[6].offset = OFFB_SSEROUND;
84523800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      d->fxState[6].size   = sizeof(UInt);
84533800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj
84543800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      /* Be paranoid ... this assertion tries to ensure the 8 %xmm
84553800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj	 images are packed back-to-back.  If not, the value of
84563800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj	 d->fxState[5].size is wrong. */
84573800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      vassert(16 == sizeof(U128));
84583800e2d3c23c6480b0bfbaf04444d6b10628b25esewardj      vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8459a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8460a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      stmt( IRStmt_Dirty(d) );
8461a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8462a0e83b06f304527e3e9aec527c344e35e7023d76sewardj      goto decode_success;
8463a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   }
8464a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
8465a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   /* ------ SSE decoder main ------ */
8466a0e83b06f304527e3e9aec527c344e35e7023d76sewardj
84679df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj   /* Skip parts of the decoder which don't apply given the stated
84689df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj      guest subarchitecture. */
84695117ce116f47141cb23d1b49cc826e19323add97sewardj   if (archinfo->hwcaps == 0/*baseline, no sse at all*/)
84709df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj      goto after_sse_decoders;
84716c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
84726c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* With mmxext only some extended MMX instructions are recognized.
84736c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      The mmxext instructions are MASKMOVQ MOVNTQ PAVGB PAVGW PMAXSW
84746c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      PMAXUB PMINSW PMINUB PMULHUW PSADBW PSHUFW PEXTRW PINSRW PMOVMSKB
84756c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      PREFETCHNTA PREFETCHT0 PREFETCHT1 PREFETCHT2 SFENCE
84766c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
84776c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      http://support.amd.com/us/Embedded_TechDocs/22466.pdf
84786c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      https://en.wikipedia.org/wiki/3DNow!#3DNow.21_extensions */
84796c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
84806c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (archinfo->hwcaps == VEX_HWCAPS_X86_MMXEXT/*integer only sse1 subset*/)
84816c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto mmxext;
84826c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
84839df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj   /* Otherwise we must be doing sse1 or sse2, so we can at least try
84849df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj      for SSE1 here. */
8485c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
8486c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
8487636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
8488129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
8489c9a43665879a03886b27a65b68af2a2c11b04f59sewardj      goto decode_success;
8490c9a43665879a03886b27a65b68af2a2c11b04f59sewardj   }
8491c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
84921e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
84931e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
84941e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      vassert(sz == 4);
8495129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
84961e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      goto decode_success;
84971e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
84981e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
84991e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   /* 0F 55 = ANDNPS -- G = (not G) and E */
8500636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
8501f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_AndV128 );
85021e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      goto decode_success;
85031e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
85041e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
85051e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   /* 0F 54 = ANDPS -- G = G and E */
8506636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
8507f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_AndV128 );
85081e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      goto decode_success;
85091e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
85101e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
85111e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
8512636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
85131e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
85141e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      goto decode_success;
85151e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
85161e6ad745ebafd0524da1da27a4b85524fa84f777sewardj
85171e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
85181e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
85191e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      vassert(sz == 4);
85201e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
85211e6ad745ebafd0524da1da27a4b85524fa84f777sewardj      goto decode_success;
85221e6ad745ebafd0524da1da27a4b85524fa84f777sewardj   }
8523c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
8524fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 0F 2F = COMISS  -- 32F0x4 comparison G,E, and set ZCP */
8525c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
8526fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
852767e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      IRTemp argL = newTemp(Ity_F32);
852867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      IRTemp argR = newTemp(Ity_F32);
852967e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      modrm = getIByte(delta+2);
853067e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      if (epartIsReg(modrm)) {
853167e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj         assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
853267e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj         delta += 2+1;
8533c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8534c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                  nameXMMReg(gregOfRM(modrm)) );
853567e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      } else {
853667e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
853767e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj	 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
853867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj         delta += 2+alen;
8539c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         DIP("[u]comiss %s,%s\n", dis_buf,
8540c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                  nameXMMReg(gregOfRM(modrm)) );
854167e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      }
854267e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
854367e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj
854467e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
854567e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
854667e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      stmt( IRStmt_Put(
854767e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj               OFFB_CC_DEP1,
854867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj               binop( Iop_And32,
854967e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj                      binop(Iop_CmpF64,
855067e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj                            unop(Iop_F32toF64,mkexpr(argL)),
855167e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj                            unop(Iop_F32toF64,mkexpr(argR))),
855267e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj                      mkU32(0x45)
855367e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj          )));
8554a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      /* Set NDEP even though it isn't used.  This makes redundant-PUT
8555a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj         elimination of previous stores to this field work better. */
8556a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
855767e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj      goto decode_success;
855867e002d10be13b4a90866b9193ab8fa8cd21c4fcsewardj   }
8559c9a43665879a03886b27a65b68af2a2c11b04f59sewardj
85604cb918d355cef4e7640d374346852db4556f3524sewardj   /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
85614cb918d355cef4e7640d374346852db4556f3524sewardj      half xmm */
8562fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
85634cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp arg64 = newTemp(Ity_I64);
85644cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp rmode = newTemp(Ity_I32);
85654cb918d355cef4e7640d374346852db4556f3524sewardj      vassert(sz == 4);
85664cb918d355cef4e7640d374346852db4556f3524sewardj
85674cb918d355cef4e7640d374346852db4556f3524sewardj      modrm = getIByte(delta+2);
85684cb918d355cef4e7640d374346852db4556f3524sewardj      do_MMX_preamble();
85694cb918d355cef4e7640d374346852db4556f3524sewardj      if (epartIsReg(modrm)) {
85704cb918d355cef4e7640d374346852db4556f3524sewardj         assign( arg64, getMMXReg(eregOfRM(modrm)) );
85714cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 2+1;
85724cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
85734cb918d355cef4e7640d374346852db4556f3524sewardj                                 nameXMMReg(gregOfRM(modrm)));
85744cb918d355cef4e7640d374346852db4556f3524sewardj      } else {
85754cb918d355cef4e7640d374346852db4556f3524sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
85764cb918d355cef4e7640d374346852db4556f3524sewardj	 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
85774cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 2+alen;
85784cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvtpi2ps %s,%s\n", dis_buf,
85794cb918d355cef4e7640d374346852db4556f3524sewardj                                 nameXMMReg(gregOfRM(modrm)) );
85804cb918d355cef4e7640d374346852db4556f3524sewardj      }
85814cb918d355cef4e7640d374346852db4556f3524sewardj
85824cb918d355cef4e7640d374346852db4556f3524sewardj      assign( rmode, get_sse_roundingmode() );
85834cb918d355cef4e7640d374346852db4556f3524sewardj
85844cb918d355cef4e7640d374346852db4556f3524sewardj      putXMMRegLane32F(
85853bca906f6e715c544eb49c278bedef093c14c0d7sewardj         gregOfRM(modrm), 0,
85863bca906f6e715c544eb49c278bedef093c14c0d7sewardj         binop(Iop_F64toF32,
85874cb918d355cef4e7640d374346852db4556f3524sewardj               mkexpr(rmode),
85886c299f3acab617581ea504e45fbb6cab24c2b29fsewardj               unop(Iop_I32StoF64,
85893bca906f6e715c544eb49c278bedef093c14c0d7sewardj                    unop(Iop_64to32, mkexpr(arg64)) )) );
85904cb918d355cef4e7640d374346852db4556f3524sewardj
85914cb918d355cef4e7640d374346852db4556f3524sewardj      putXMMRegLane32F(
85924cb918d355cef4e7640d374346852db4556f3524sewardj         gregOfRM(modrm), 1,
85933bca906f6e715c544eb49c278bedef093c14c0d7sewardj         binop(Iop_F64toF32,
85944cb918d355cef4e7640d374346852db4556f3524sewardj               mkexpr(rmode),
85956c299f3acab617581ea504e45fbb6cab24c2b29fsewardj               unop(Iop_I32StoF64,
85963bca906f6e715c544eb49c278bedef093c14c0d7sewardj                    unop(Iop_64HIto32, mkexpr(arg64)) )) );
85974cb918d355cef4e7640d374346852db4556f3524sewardj
85984cb918d355cef4e7640d374346852db4556f3524sewardj      goto decode_success;
85994cb918d355cef4e7640d374346852db4556f3524sewardj   }
86004cb918d355cef4e7640d374346852db4556f3524sewardj
86014cb918d355cef4e7640d374346852db4556f3524sewardj   /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
86024cb918d355cef4e7640d374346852db4556f3524sewardj      quarter xmm */
86034cb918d355cef4e7640d374346852db4556f3524sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
86044cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp arg32 = newTemp(Ity_I32);
86054cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp rmode = newTemp(Ity_I32);
86064cb918d355cef4e7640d374346852db4556f3524sewardj      vassert(sz == 4);
86074cb918d355cef4e7640d374346852db4556f3524sewardj
86084cb918d355cef4e7640d374346852db4556f3524sewardj      modrm = getIByte(delta+3);
86094cb918d355cef4e7640d374346852db4556f3524sewardj      if (epartIsReg(modrm)) {
86104cb918d355cef4e7640d374346852db4556f3524sewardj         assign( arg32, getIReg(4, eregOfRM(modrm)) );
86114cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 3+1;
86124cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
86134cb918d355cef4e7640d374346852db4556f3524sewardj                                 nameXMMReg(gregOfRM(modrm)));
86144cb918d355cef4e7640d374346852db4556f3524sewardj      } else {
86154cb918d355cef4e7640d374346852db4556f3524sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
86164cb918d355cef4e7640d374346852db4556f3524sewardj	 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
86174cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 3+alen;
86184cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvtsi2ss %s,%s\n", dis_buf,
86194cb918d355cef4e7640d374346852db4556f3524sewardj                                 nameXMMReg(gregOfRM(modrm)) );
86204cb918d355cef4e7640d374346852db4556f3524sewardj      }
86214cb918d355cef4e7640d374346852db4556f3524sewardj
86224cb918d355cef4e7640d374346852db4556f3524sewardj      assign( rmode, get_sse_roundingmode() );
86234cb918d355cef4e7640d374346852db4556f3524sewardj
86244cb918d355cef4e7640d374346852db4556f3524sewardj      putXMMRegLane32F(
86253bca906f6e715c544eb49c278bedef093c14c0d7sewardj         gregOfRM(modrm), 0,
86263bca906f6e715c544eb49c278bedef093c14c0d7sewardj         binop(Iop_F64toF32,
86273bca906f6e715c544eb49c278bedef093c14c0d7sewardj               mkexpr(rmode),
86286c299f3acab617581ea504e45fbb6cab24c2b29fsewardj               unop(Iop_I32StoF64, mkexpr(arg32)) ) );
86294cb918d355cef4e7640d374346852db4556f3524sewardj
86304cb918d355cef4e7640d374346852db4556f3524sewardj      goto decode_success;
86314cb918d355cef4e7640d374346852db4556f3524sewardj   }
86324cb918d355cef4e7640d374346852db4556f3524sewardj
86334cb918d355cef4e7640d374346852db4556f3524sewardj   /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
86344cb918d355cef4e7640d374346852db4556f3524sewardj      I32 in mmx, according to prevailing SSE rounding mode */
86354cb918d355cef4e7640d374346852db4556f3524sewardj   /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
86364cb918d355cef4e7640d374346852db4556f3524sewardj      I32 in mmx, rounding towards zero */
8637fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
86384cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp dst64  = newTemp(Ity_I64);
86394cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp rmode  = newTemp(Ity_I32);
86404cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp f32lo  = newTemp(Ity_F32);
86414cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp f32hi  = newTemp(Ity_F32);
86422d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool   r2zero = toBool(insn[1] == 0x2C);
86434cb918d355cef4e7640d374346852db4556f3524sewardj
86444cb918d355cef4e7640d374346852db4556f3524sewardj      do_MMX_preamble();
86454cb918d355cef4e7640d374346852db4556f3524sewardj      modrm = getIByte(delta+2);
86464cb918d355cef4e7640d374346852db4556f3524sewardj
86474cb918d355cef4e7640d374346852db4556f3524sewardj      if (epartIsReg(modrm)) {
86484cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 2+1;
86494cb918d355cef4e7640d374346852db4556f3524sewardj	 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
86504cb918d355cef4e7640d374346852db4556f3524sewardj	 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
86514cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
86524cb918d355cef4e7640d374346852db4556f3524sewardj                                   nameXMMReg(eregOfRM(modrm)),
86534cb918d355cef4e7640d374346852db4556f3524sewardj                                   nameMMXReg(gregOfRM(modrm)));
86544cb918d355cef4e7640d374346852db4556f3524sewardj      } else {
86554cb918d355cef4e7640d374346852db4556f3524sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
86564cb918d355cef4e7640d374346852db4556f3524sewardj	 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
86574cb918d355cef4e7640d374346852db4556f3524sewardj	 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
86584cb918d355cef4e7640d374346852db4556f3524sewardj                                              mkexpr(addr),
86594cb918d355cef4e7640d374346852db4556f3524sewardj                                              mkU32(4) )));
86604cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 2+alen;
86614cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
86624cb918d355cef4e7640d374346852db4556f3524sewardj                                   dis_buf,
86634cb918d355cef4e7640d374346852db4556f3524sewardj                                   nameMMXReg(gregOfRM(modrm)));
86644cb918d355cef4e7640d374346852db4556f3524sewardj      }
86654cb918d355cef4e7640d374346852db4556f3524sewardj
86664cb918d355cef4e7640d374346852db4556f3524sewardj      if (r2zero) {
86674cb918d355cef4e7640d374346852db4556f3524sewardj         assign(rmode, mkU32((UInt)Irrm_ZERO) );
86684cb918d355cef4e7640d374346852db4556f3524sewardj      } else {
86694cb918d355cef4e7640d374346852db4556f3524sewardj         assign( rmode, get_sse_roundingmode() );
86704cb918d355cef4e7640d374346852db4556f3524sewardj      }
86714cb918d355cef4e7640d374346852db4556f3524sewardj
86724cb918d355cef4e7640d374346852db4556f3524sewardj      assign(
86734cb918d355cef4e7640d374346852db4556f3524sewardj         dst64,
86744cb918d355cef4e7640d374346852db4556f3524sewardj         binop( Iop_32HLto64,
86756c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                binop( Iop_F64toI32S,
86764cb918d355cef4e7640d374346852db4556f3524sewardj                       mkexpr(rmode),
86774cb918d355cef4e7640d374346852db4556f3524sewardj                       unop( Iop_F32toF64, mkexpr(f32hi) ) ),
86786c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                binop( Iop_F64toI32S,
86794cb918d355cef4e7640d374346852db4556f3524sewardj                       mkexpr(rmode),
86804cb918d355cef4e7640d374346852db4556f3524sewardj                       unop( Iop_F32toF64, mkexpr(f32lo) ) )
86814cb918d355cef4e7640d374346852db4556f3524sewardj              )
86824cb918d355cef4e7640d374346852db4556f3524sewardj      );
86834cb918d355cef4e7640d374346852db4556f3524sewardj
86844cb918d355cef4e7640d374346852db4556f3524sewardj      putMMXReg(gregOfRM(modrm), mkexpr(dst64));
86854cb918d355cef4e7640d374346852db4556f3524sewardj      goto decode_success;
86864cb918d355cef4e7640d374346852db4556f3524sewardj   }
86874cb918d355cef4e7640d374346852db4556f3524sewardj
86884cb918d355cef4e7640d374346852db4556f3524sewardj   /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
86894cb918d355cef4e7640d374346852db4556f3524sewardj      I32 in ireg, according to prevailing SSE rounding mode */
86904cb918d355cef4e7640d374346852db4556f3524sewardj   /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
86910b21044f0cbfd84788247ed7ba65cf77ea832a2csewardj      I32 in ireg, rounding towards zero */
86924cb918d355cef4e7640d374346852db4556f3524sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F
86934cb918d355cef4e7640d374346852db4556f3524sewardj       && (insn[2] == 0x2D || insn[2] == 0x2C)) {
86944cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp rmode = newTemp(Ity_I32);
86954cb918d355cef4e7640d374346852db4556f3524sewardj      IRTemp f32lo = newTemp(Ity_F32);
86962d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool   r2zero = toBool(insn[2] == 0x2C);
86974cb918d355cef4e7640d374346852db4556f3524sewardj      vassert(sz == 4);
86984cb918d355cef4e7640d374346852db4556f3524sewardj
86994cb918d355cef4e7640d374346852db4556f3524sewardj      modrm = getIByte(delta+3);
87004cb918d355cef4e7640d374346852db4556f3524sewardj      if (epartIsReg(modrm)) {
87014cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 3+1;
87024cb918d355cef4e7640d374346852db4556f3524sewardj	 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
87034cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
87044cb918d355cef4e7640d374346852db4556f3524sewardj                                   nameXMMReg(eregOfRM(modrm)),
87054cb918d355cef4e7640d374346852db4556f3524sewardj                                   nameIReg(4, gregOfRM(modrm)));
87064cb918d355cef4e7640d374346852db4556f3524sewardj      } else {
87074cb918d355cef4e7640d374346852db4556f3524sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
87084cb918d355cef4e7640d374346852db4556f3524sewardj	 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
87094cb918d355cef4e7640d374346852db4556f3524sewardj         delta += 3+alen;
87104cb918d355cef4e7640d374346852db4556f3524sewardj         DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
87114cb918d355cef4e7640d374346852db4556f3524sewardj                                   dis_buf,
87124cb918d355cef4e7640d374346852db4556f3524sewardj                                   nameIReg(4, gregOfRM(modrm)));
87134cb918d355cef4e7640d374346852db4556f3524sewardj      }
87144cb918d355cef4e7640d374346852db4556f3524sewardj
87154cb918d355cef4e7640d374346852db4556f3524sewardj      if (r2zero) {
87167df596b1e36840e2d74c90aa55589934add61ccfsewardj         assign( rmode, mkU32((UInt)Irrm_ZERO) );
87174cb918d355cef4e7640d374346852db4556f3524sewardj      } else {
87184cb918d355cef4e7640d374346852db4556f3524sewardj         assign( rmode, get_sse_roundingmode() );
87194cb918d355cef4e7640d374346852db4556f3524sewardj      }
87204cb918d355cef4e7640d374346852db4556f3524sewardj
87214cb918d355cef4e7640d374346852db4556f3524sewardj      putIReg(4, gregOfRM(modrm),
87226c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                 binop( Iop_F64toI32S,
87234cb918d355cef4e7640d374346852db4556f3524sewardj                        mkexpr(rmode),
87244cb918d355cef4e7640d374346852db4556f3524sewardj                        unop( Iop_F32toF64, mkexpr(f32lo) ) )
87254cb918d355cef4e7640d374346852db4556f3524sewardj      );
87264cb918d355cef4e7640d374346852db4556f3524sewardj
87274cb918d355cef4e7640d374346852db4556f3524sewardj      goto decode_success;
87284cb918d355cef4e7640d374346852db4556f3524sewardj   }
87294cb918d355cef4e7640d374346852db4556f3524sewardj
8730176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
8731fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
8732129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
8733176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj      goto decode_success;
8734176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   }
8735176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj
8736176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8737176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
8738176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj      vassert(sz == 4);
8739129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
8740176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj      goto decode_success;
8741176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   }
8742176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj
87437df596b1e36840e2d74c90aa55589934add61ccfsewardj   /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
87447df596b1e36840e2d74c90aa55589934add61ccfsewardj   if (insn[0] == 0x0F && insn[1] == 0xAE
87457df596b1e36840e2d74c90aa55589934add61ccfsewardj       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
87467df596b1e36840e2d74c90aa55589934add61ccfsewardj
87477df596b1e36840e2d74c90aa55589934add61ccfsewardj      IRTemp t64 = newTemp(Ity_I64);
87487df596b1e36840e2d74c90aa55589934add61ccfsewardj      IRTemp ew = newTemp(Ity_I32);
87497df596b1e36840e2d74c90aa55589934add61ccfsewardj
87507df596b1e36840e2d74c90aa55589934add61ccfsewardj      modrm = getIByte(delta+2);
87517df596b1e36840e2d74c90aa55589934add61ccfsewardj      vassert(!epartIsReg(modrm));
87527df596b1e36840e2d74c90aa55589934add61ccfsewardj      vassert(sz == 4);
87537df596b1e36840e2d74c90aa55589934add61ccfsewardj
87547df596b1e36840e2d74c90aa55589934add61ccfsewardj      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
87557df596b1e36840e2d74c90aa55589934add61ccfsewardj      delta += 2+alen;
875633dd31b1bcc175495b96222fa278062fd6116899sewardj      DIP("ldmxcsr %s\n", dis_buf);
87577df596b1e36840e2d74c90aa55589934add61ccfsewardj
87587df596b1e36840e2d74c90aa55589934add61ccfsewardj      /* The only thing we observe in %mxcsr is the rounding mode.
87597df596b1e36840e2d74c90aa55589934add61ccfsewardj         Therefore, pass the 32-bit value (SSE native-format control
87607df596b1e36840e2d74c90aa55589934add61ccfsewardj         word) to a clean helper, getting back a 64-bit value, the
87617df596b1e36840e2d74c90aa55589934add61ccfsewardj         lower half of which is the SSEROUND value to store, and the
87627df596b1e36840e2d74c90aa55589934add61ccfsewardj         upper half of which is the emulation-warning token which may
87637df596b1e36840e2d74c90aa55589934add61ccfsewardj         be generated.
87647df596b1e36840e2d74c90aa55589934add61ccfsewardj      */
87657df596b1e36840e2d74c90aa55589934add61ccfsewardj      /* ULong x86h_check_ldmxcsr ( UInt ); */
87667df596b1e36840e2d74c90aa55589934add61ccfsewardj      assign( t64, mkIRExprCCall(
87677df596b1e36840e2d74c90aa55589934add61ccfsewardj                      Ity_I64, 0/*regparms*/,
87683bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                      "x86g_check_ldmxcsr",
87693bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                      &x86g_check_ldmxcsr,
87707df596b1e36840e2d74c90aa55589934add61ccfsewardj                      mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
87717df596b1e36840e2d74c90aa55589934add61ccfsewardj                   )
87727df596b1e36840e2d74c90aa55589934add61ccfsewardj            );
87737df596b1e36840e2d74c90aa55589934add61ccfsewardj
8774636ad762e49597ef608323f27c7b8eb66962cd90sewardj      put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
87757df596b1e36840e2d74c90aa55589934add61ccfsewardj      assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
87767df596b1e36840e2d74c90aa55589934add61ccfsewardj      put_emwarn( mkexpr(ew) );
87777df596b1e36840e2d74c90aa55589934add61ccfsewardj      /* Finally, if an emulation warning was reported, side-exit to
87787df596b1e36840e2d74c90aa55589934add61ccfsewardj         the next insn, reporting the warning, so that Valgrind's
87797df596b1e36840e2d74c90aa55589934add61ccfsewardj         dispatcher sees the warning. */
87807df596b1e36840e2d74c90aa55589934add61ccfsewardj      stmt(
87817df596b1e36840e2d74c90aa55589934add61ccfsewardj         IRStmt_Exit(
87827df596b1e36840e2d74c90aa55589934add61ccfsewardj            binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
87837df596b1e36840e2d74c90aa55589934add61ccfsewardj            Ijk_EmWarn,
8784c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
8785c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            OFFB_EIP
87867df596b1e36840e2d74c90aa55589934add61ccfsewardj         )
87877df596b1e36840e2d74c90aa55589934add61ccfsewardj      );
87887df596b1e36840e2d74c90aa55589934add61ccfsewardj      goto decode_success;
87897df596b1e36840e2d74c90aa55589934add61ccfsewardj   }
87907df596b1e36840e2d74c90aa55589934add61ccfsewardj
87916c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
87926c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* mmxext sse1 subset starts here. mmxext only arches will parse
87936c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      only this subset of the sse1 instructions. */
87946c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw  mmxext:
87956c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
8796d71ba837242cc470f622335b1c650bce8886a533sewardj   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8797d71ba837242cc470f622335b1c650bce8886a533sewardj   /* 0F F7 = MASKMOVQ -- 8x8 masked store */
8798d71ba837242cc470f622335b1c650bce8886a533sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF7) {
8799d71ba837242cc470f622335b1c650bce8886a533sewardj      Bool ok = False;
8800d71ba837242cc470f622335b1c650bce8886a533sewardj      delta = dis_MMX( &ok, sorb, sz, delta+1 );
8801d71ba837242cc470f622335b1c650bce8886a533sewardj      if (!ok)
8802d71ba837242cc470f622335b1c650bce8886a533sewardj         goto decode_failure;
8803d71ba837242cc470f622335b1c650bce8886a533sewardj      goto decode_success;
8804d71ba837242cc470f622335b1c650bce8886a533sewardj   }
8805d71ba837242cc470f622335b1c650bce8886a533sewardj
88066c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
88076c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F E7 = MOVNTQ -- for us, just a plain MMX store.  Note, the
88086c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      Intel manual does not say anything about the usual business of
88096c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      the FP reg tags getting trashed whenever an MMX insn happens.
88106c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      So we just leave them alone.
88116c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   */
88126c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0xE7) {
88136c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+2);
88146c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (sz == 4 && !epartIsReg(modrm)) {
88156c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         /* do_MMX_preamble(); Intel docs don't specify this */
88166c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
88176c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
88186c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movntq %s,%s\n", dis_buf,
88196c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                               nameMMXReg(gregOfRM(modrm)));
88206c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+alen;
88216c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
88226c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
88236c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* else fall through */
8824176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   }
8825176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj
88266c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
88276c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
88286c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
88296c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
88306c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
88316c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pavgb", False );
8832176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj      goto decode_success;
8833176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   }
8834176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj
88356c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
88366c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
88376c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
88386c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
88396c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
88406c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pavgw", False );
8841176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj      goto decode_success;
8842176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   }
8843176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj
88446c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
88456c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
88466c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      zero-extend of it in ireg(G). */
88476c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0xC5) {
88486c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = insn[2];
88496c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (sz == 4 && epartIsReg(modrm)) {
88506c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         IRTemp sV = newTemp(Ity_I64);
88516c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t5 = newTemp(Ity_I16);
88526c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         do_MMX_preamble();
88536c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign(sV, getMMXReg(eregOfRM(modrm)));
88546c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         breakup64to16s( sV, &t3, &t2, &t1, &t0 );
88556c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         switch (insn[3] & 3) {
88566c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            case 0:  assign(t5, mkexpr(t0)); break;
88576c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            case 1:  assign(t5, mkexpr(t1)); break;
88586c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            case 2:  assign(t5, mkexpr(t2)); break;
88596c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            case 3:  assign(t5, mkexpr(t3)); break;
88606c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            default: vassert(0); /*NOTREACHED*/
88616c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         }
88626c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
88636c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("pextrw $%d,%s,%s\n",
88646c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw             (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
88656c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                           nameIReg(4,gregOfRM(modrm)));
88666c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 4;
88676c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
88686c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
88696c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* else fall through */
8870176a59c6eec21f8a0e8dbafdf85bb9af8109b0c6sewardj   }
88714cb918d355cef4e7640d374346852db4556f3524sewardj
88726c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
88736c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
88746c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      put it into the specified lane of mmx(G). */
88756c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
88766c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
88776c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         mmx reg.  t4 is the new lane value.  t5 is the original
88786c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         mmx value. t6 is the new mmx value. */
88796c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      Int lane;
88806c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      t4 = newTemp(Ity_I16);
88816c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      t5 = newTemp(Ity_I64);
88826c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      t6 = newTemp(Ity_I64);
88836c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = insn[2];
88846c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
88856c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
88866c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      assign(t5, getMMXReg(gregOfRM(modrm)));
88876c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      breakup64to16s( t5, &t3, &t2, &t1, &t0 );
88886c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
88899636b44102bd3f79cba764576f34931d7b584d9esewardj      if (epartIsReg(modrm)) {
88906c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign(t4, getIReg(2, eregOfRM(modrm)));
88916c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 3+1;
88926c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         lane = insn[3+1-1];
88936c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
88946c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   nameIReg(2,eregOfRM(modrm)),
88956c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   nameMMXReg(gregOfRM(modrm)));
88969636b44102bd3f79cba764576f34931d7b584d9esewardj      } else {
88979636b44102bd3f79cba764576f34931d7b584d9esewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
88986c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 3+alen;
88996c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         lane = insn[3+alen-1];
89006c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign(t4, loadLE(Ity_I16, mkexpr(addr)));
89016c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
89026c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   dis_buf,
89036c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   nameMMXReg(gregOfRM(modrm)));
89046c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
89056c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
89066c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      switch (lane & 3) {
89076c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 0:  assign(t6, mk64from16s(t3,t2,t1,t4)); break;
89086c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 1:  assign(t6, mk64from16s(t3,t2,t4,t0)); break;
89096c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 2:  assign(t6, mk64from16s(t3,t4,t1,t0)); break;
89106c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 3:  assign(t6, mk64from16s(t4,t2,t1,t0)); break;
89116c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         default: vassert(0); /*NOTREACHED*/
89129636b44102bd3f79cba764576f34931d7b584d9esewardj      }
89136c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      putMMXReg(gregOfRM(modrm), mkexpr(t6));
89149636b44102bd3f79cba764576f34931d7b584d9esewardj      goto decode_success;
89159636b44102bd3f79cba764576f34931d7b584d9esewardj   }
89169636b44102bd3f79cba764576f34931d7b584d9esewardj
89176c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
89186c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F EE = PMAXSW -- 16x4 signed max */
89196c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
89206c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
89216c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
89226c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pmaxsw", False );
89236c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
892409f415512b3b874475a4ec78e15cf87712b49b7bsewardj   }
892509f415512b3b874475a4ec78e15cf87712b49b7bsewardj
89266c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
89276c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F DE = PMAXUB -- 8x8 unsigned max */
89286c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
89296c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
89306c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
89316c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pmaxub", False );
89320bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      goto decode_success;
89330bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
89340bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
89356c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
89366c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F EA = PMINSW -- 16x4 signed min */
89376c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
89386c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
89396c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
89406c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pminsw", False );
89416c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
89420bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
89430bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
89446c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
89456c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F DA = PMINUB -- 8x8 unsigned min */
89466c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
89476c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
89486c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
89496c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pminub", False );
89500bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      goto decode_success;
89510bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
89520bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
89536c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
89546c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
89556c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      mmx(E), turn them into a byte, and put zero-extend of it in
89566c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      ireg(G). */
89576c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
89586c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = insn[2];
89596c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (epartIsReg(modrm)) {
89606c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         do_MMX_preamble();
89616c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t0 = newTemp(Ity_I64);
89626c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t1 = newTemp(Ity_I32);
89636c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign(t0, getMMXReg(eregOfRM(modrm)));
89646c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign(t1, unop(Iop_8Uto32, unop(Iop_GetMSBs8x8, mkexpr(t0))));
89656c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putIReg(4, gregOfRM(modrm), mkexpr(t1));
89666c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
89676c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                 nameIReg(4,gregOfRM(modrm)));
89686c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 3;
89690bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj         goto decode_success;
89706c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
89710bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      /* else fall through */
89720bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
89730bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
89746c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
89756c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
89766c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
89776c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
89786c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
89796c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                sorb, delta+2, insn[1], "pmuluh", False );
89806c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
89819636b44102bd3f79cba764576f34931d7b584d9esewardj   }
89829636b44102bd3f79cba764576f34931d7b584d9esewardj
89836c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
89846c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 18 /1 = PREFETCH0   -- with various different hints */
89856c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 18 /2 = PREFETCH1 */
89866c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 18 /3 = PREFETCH2 */
89876c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0x18
89886c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw       && !epartIsReg(insn[2])
89896c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw       && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
89906c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      const HChar* hintstr = "??";
89916c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
89929636b44102bd3f79cba764576f34931d7b584d9esewardj      modrm = getIByte(delta+2);
89936c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(!epartIsReg(modrm));
89946c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
89956c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
89966c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta += 2+alen;
89976c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
89986c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      switch (gregOfRM(modrm)) {
89996c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 0: hintstr = "nta"; break;
90006c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 1: hintstr = "t0"; break;
90016c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 2: hintstr = "t1"; break;
90026c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 3: hintstr = "t2"; break;
90036c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         default: vassert(0); /*NOTREACHED*/
90049636b44102bd3f79cba764576f34931d7b584d9esewardj      }
90056c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90066c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      DIP("prefetch%s %s\n", hintstr, dis_buf);
90076c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
90089636b44102bd3f79cba764576f34931d7b584d9esewardj   }
90099636b44102bd3f79cba764576f34931d7b584d9esewardj
90106c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 0D /0 = PREFETCH  m8 -- 3DNow! prefetch */
90116c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 0D /1 = PREFETCHW m8 -- ditto, with some other hint */
90126c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0x0D
90136c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw       && !epartIsReg(insn[2])
90146c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw       && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 1) {
90156c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      const HChar* hintstr = "??";
90166c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90179636b44102bd3f79cba764576f34931d7b584d9esewardj      modrm = getIByte(delta+2);
90186c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(!epartIsReg(modrm));
90196c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90206c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
90216c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta += 2+alen;
90226c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90236c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      switch (gregOfRM(modrm)) {
90246c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 0: hintstr = ""; break;
90256c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         case 1: hintstr = "w"; break;
90266c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         default: vassert(0); /*NOTREACHED*/
90279636b44102bd3f79cba764576f34931d7b584d9esewardj      }
90286c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90296c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      DIP("prefetch%s %s\n", hintstr, dis_buf);
90306c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
90319636b44102bd3f79cba764576f34931d7b584d9esewardj   }
90329636b44102bd3f79cba764576f34931d7b584d9esewardj
90336c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
90346c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
90356c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF6) {
90366c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
90376c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_MMXop_regmem_to_reg (
90386c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                 sorb, delta+2, insn[1], "psadbw", False );
90399636b44102bd3f79cba764576f34931d7b584d9esewardj      goto decode_success;
90409636b44102bd3f79cba764576f34931d7b584d9esewardj   }
90419636b44102bd3f79cba764576f34931d7b584d9esewardj
90426c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
90436c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
90446c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
90456c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      Int order;
90466c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      IRTemp sV, dV, s3, s2, s1, s0;
90476c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      s3 = s2 = s1 = s0 = IRTemp_INVALID;
90486c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      sV = newTemp(Ity_I64);
90496c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      dV = newTemp(Ity_I64);
90506c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      do_MMX_preamble();
90516c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = insn[2];
90529636b44102bd3f79cba764576f34931d7b584d9esewardj      if (epartIsReg(modrm)) {
90536c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign( sV, getMMXReg(eregOfRM(modrm)) );
90546c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         order = (Int)insn[3];
90556c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+2;
90566c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("pshufw $%d,%s,%s\n", order,
90576c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   nameMMXReg(eregOfRM(modrm)),
90586c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   nameMMXReg(gregOfRM(modrm)));
90599636b44102bd3f79cba764576f34931d7b584d9esewardj      } else {
90606c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
90616c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
90626c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw	 order = (Int)insn[2+alen];
90639636b44102bd3f79cba764576f34931d7b584d9esewardj         delta += 3+alen;
90646c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("pshufw $%d,%s,%s\n", order,
90656c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   dis_buf,
90666c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   nameMMXReg(gregOfRM(modrm)));
90679636b44102bd3f79cba764576f34931d7b584d9esewardj      }
90686c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      breakup64to16s( sV, &s3, &s2, &s1, &s0 );
90699636b44102bd3f79cba764576f34931d7b584d9esewardj
90706c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw#     define SEL(n) \
90716c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
90726c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      assign(dV,
90736c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
90746c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          SEL((order>>2)&3), SEL((order>>0)&3) )
90756c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      );
90766c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      putMMXReg(gregOfRM(modrm), mkexpr(dV));
90776c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw#     undef SEL
90789636b44102bd3f79cba764576f34931d7b584d9esewardj      goto decode_success;
90799636b44102bd3f79cba764576f34931d7b584d9esewardj   }
90809636b44102bd3f79cba764576f34931d7b584d9esewardj
90816c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F AE /7 = SFENCE -- flush pending operations to memory */
90826c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0xAE
90836c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw       && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
90849636b44102bd3f79cba764576f34931d7b584d9esewardj      vassert(sz == 4);
90856c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta += 3;
90866c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* Insert a memory fence.  It's sometimes important that these
90876c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         are carried through to the generated code. */
90886c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      stmt( IRStmt_MBE(Imbe_Fence) );
90896c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      DIP("sfence\n");
90909636b44102bd3f79cba764576f34931d7b584d9esewardj      goto decode_success;
90919636b44102bd3f79cba764576f34931d7b584d9esewardj   }
90929636b44102bd3f79cba764576f34931d7b584d9esewardj
90936c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* End of mmxext sse1 subset. No more sse parsing for mmxext only arches. */
90946c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (archinfo->hwcaps == VEX_HWCAPS_X86_MMXEXT/*integer only sse1 subset*/)
90956c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto after_sse_decoders;
90966c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90976c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
90986c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
90996c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
91006c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
91019636b44102bd3f79cba764576f34931d7b584d9esewardj      goto decode_success;
91029636b44102bd3f79cba764576f34931d7b584d9esewardj   }
91039636b44102bd3f79cba764576f34931d7b584d9esewardj
91046c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
91056c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
91066c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(sz == 4);
91076c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
9108b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      goto decode_success;
9109b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9110b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
91116c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
91126c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
91136c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
9114b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      goto decode_success;
9115b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9116b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
91176c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
91186c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
91196c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(sz == 4);
91206c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
91216c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
9122b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9123b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
91246c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
91256c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
91266c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
91276c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+2);
9128e5854d6d470f21677ec84f71d09129434b044246sewardj      if (epartIsReg(modrm)) {
91296c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMReg( gregOfRM(modrm),
91306c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                    getXMMReg( eregOfRM(modrm) ));
91316c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
91326c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                  nameXMMReg(gregOfRM(modrm)));
91336c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+1;
9134e5854d6d470f21677ec84f71d09129434b044246sewardj      } else {
91357420b0969284c2e6d7421204d29b1bc2b1234ed6sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
91366c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         if (insn[1] == 0x28/*movaps*/)
91376c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            gen_SEGV_if_not_16_aligned( addr );
91386c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMReg( gregOfRM(modrm),
91396c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                    loadLE(Ity_V128, mkexpr(addr)) );
91406c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("mov[ua]ps %s,%s\n", dis_buf,
91416c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                  nameXMMReg(gregOfRM(modrm)));
91426c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+alen;
9143b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      }
9144e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
9145b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9146b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
91476c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
91486c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
91496c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F
91506c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw       && (insn[1] == 0x29 || insn[1] == 0x11)) {
91516c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+2);
91526c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (epartIsReg(modrm)) {
91536c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         /* fall through; awaiting test case */
91546c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      } else {
91556c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
91566c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         if (insn[1] == 0x29/*movaps*/)
91576c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            gen_SEGV_if_not_16_aligned( addr );
91586c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
91596c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRM(modrm)),
91606c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                  dis_buf );
91616c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+alen;
91626c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
91636c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
91643bca906f6e715c544eb49c278bedef093c14c0d7sewardj   }
91653bca906f6e715c544eb49c278bedef093c14c0d7sewardj
91666c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
91676c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
91686c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
91696c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+2);
91706c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (epartIsReg(modrm)) {
91716c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+1;
91726c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
91736c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          getXMMRegLane64( eregOfRM(modrm), 0 ) );
91746c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
91756c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                               nameXMMReg(gregOfRM(modrm)));
91766c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      } else {
91776c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
91786c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+alen;
91796c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
91806c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          loadLE(Ity_I64, mkexpr(addr)) );
91816c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movhps %s,%s\n", dis_buf,
91826c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                               nameXMMReg( gregOfRM(modrm) ));
91836c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
9184b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      goto decode_success;
9185b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9186b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
91876c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
91886c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
91896c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (!epartIsReg(insn[2])) {
91906c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2;
91916c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta, dis_buf );
91926c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += alen;
91936c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         storeLE( mkexpr(addr),
91946c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                  getXMMRegLane64( gregOfRM(insn[2]),
91956c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   1/*upper lane*/ ) );
91966c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
91976c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                               dis_buf);
91986c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
91996c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
92006c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* else fall through */
9201b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9202b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
92036c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
92046c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
92056c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
92066c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+2);
92076c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (epartIsReg(modrm)) {
92086c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+1;
92096c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane64( gregOfRM(modrm),
92106c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          0/*lower lane*/,
92116c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          getXMMRegLane64( eregOfRM(modrm), 1 ));
92126c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
92136c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                 nameXMMReg(gregOfRM(modrm)));
92146c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      } else {
92156c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
92166c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+alen;
92176c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane64( gregOfRM(modrm),  0/*lower lane*/,
92186c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          loadLE(Ity_I64, mkexpr(addr)) );
92196c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movlps %s, %s\n",
92206c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw             dis_buf, nameXMMReg( gregOfRM(modrm) ));
92216c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
9222b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      goto decode_success;
9223b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9224b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
92256c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
92266c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
92276c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (!epartIsReg(insn[2])) {
92286c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2;
92296c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta, dis_buf );
92306c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += alen;
92316c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         storeLE( mkexpr(addr),
92326c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                  getXMMRegLane64( gregOfRM(insn[2]),
92336c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                   0/*lower lane*/ ) );
92346c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
92356c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                dis_buf);
9236b54520819b40c3fe907725b56bcd8db5112c0b9asewardj         goto decode_success;
92376c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
9238b54520819b40c3fe907725b56bcd8db5112c0b9asewardj      /* else fall through */
9239b54520819b40c3fe907725b56bcd8db5112c0b9asewardj   }
9240b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
92416c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
92426c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      to 4 lowest bits of ireg(G) */
92436c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0x50) {
92447df596b1e36840e2d74c90aa55589934add61ccfsewardj      modrm = getIByte(delta+2);
92456c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (sz == 4 && epartIsReg(modrm)) {
92466c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         Int src;
92476c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t0 = newTemp(Ity_I32);
92486c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t1 = newTemp(Ity_I32);
92496c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t2 = newTemp(Ity_I32);
92506c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         t3 = newTemp(Ity_I32);
92516c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+1;
92526c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         src = eregOfRM(modrm);
92536c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign( t0, binop( Iop_And32,
92546c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
92556c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            mkU32(1) ));
92566c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign( t1, binop( Iop_And32,
92576c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
92586c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            mkU32(2) ));
92596c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign( t2, binop( Iop_And32,
92606c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
92616c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            mkU32(4) ));
92626c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         assign( t3, binop( Iop_And32,
92636c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
92646c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                            mkU32(8) ));
92656c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putIReg(4, gregOfRM(modrm),
92666c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                    binop(Iop_Or32,
92676c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
92686c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
92696c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                         )
92706c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                 );
92716c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movmskps %s,%s\n", nameXMMReg(src),
92726c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                 nameIReg(4, gregOfRM(modrm)));
92736c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
92747df596b1e36840e2d74c90aa55589934add61ccfsewardj      }
92756c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* else fall through */
92767df596b1e36840e2d74c90aa55589934add61ccfsewardj   }
92777df596b1e36840e2d74c90aa55589934add61ccfsewardj
92786c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
92796c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
92806c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0x0F && insn[1] == 0x2B) {
92818531768c63e46cf1ab91c20d604b05d9f90abddfsewardj      modrm = getIByte(delta+2);
92826c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (!epartIsReg(modrm)) {
92836c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
92846c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         gen_SEGV_if_not_16_aligned( addr );
92856c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
92866c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
92876c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                 dis_buf,
92886c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                                 nameXMMReg(gregOfRM(modrm)));
92896c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 2+alen;
92906c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
92918531768c63e46cf1ab91c20d604b05d9f90abddfsewardj      }
92926c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      /* else fall through */
92938531768c63e46cf1ab91c20d604b05d9f90abddfsewardj   }
92948531768c63e46cf1ab91c20d604b05d9f90abddfsewardj
92956c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
92966c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      (lo 1/4 xmm).  If E is mem, upper 3/4 of G is zeroed out. */
92976c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
92986c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(sz == 4);
92996c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+3);
93006c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      if (epartIsReg(modrm)) {
93016c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane32( gregOfRM(modrm), 0,
93026c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          getXMMRegLane32( eregOfRM(modrm), 0 ));
93036c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
93046c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                              nameXMMReg(gregOfRM(modrm)));
93056c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 3+1;
93066c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      } else {
93076c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
93086c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         /* zero bits 127:64 */
93096c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
93106c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         /* zero bits 63:32 */
93116c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane32( gregOfRM(modrm), 1, mkU32(0) );
93126c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         /* write bits 31:0 */
93136c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         putXMMRegLane32( gregOfRM(modrm), 0,
93146c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                          loadLE(Ity_I32, mkexpr(addr)) );
93156c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movss %s,%s\n", dis_buf,
93166c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                              nameXMMReg(gregOfRM(modrm)));
93176c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         delta += 3+alen;
93186c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      }
93190bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      goto decode_success;
93200bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
93210bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
93226c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
93236c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      or lo 1/4 xmm). */
93246c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
93256c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(sz == 4);
93266c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      modrm = getIByte(delta+3);
93270bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      if (epartIsReg(modrm)) {
93286c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         /* fall through, we don't yet have a test case */
93290bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      } else {
93306c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
93316c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         storeLE( mkexpr(addr),
93326c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                  getXMMRegLane32(gregOfRM(modrm), 0) );
93336c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)),
93346c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw                              dis_buf);
93350bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj         delta += 3+alen;
93366c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         goto decode_success;
93370bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      }
93386c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   }
93390bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
93406c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
93416c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
93426c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
93436c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
93446c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   }
93456c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
93466c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
93476c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
93486c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      vassert(sz == 4);
93496c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
93506c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      goto decode_success;
93516c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   }
93526c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw
93536c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   /* 0F 56 = ORPS -- G = G and E */
93546c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
93556c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw      delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_OrV128 );
93560bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      goto decode_success;
93570bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
93580bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
93590bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
93600bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   if (insn[0] == 0x0F && insn[1] == 0x53) {
93610bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      vassert(sz == 4);
9362129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
93631ddee21008ffdb2ac7f8e6a73445f150f753606fsewardj                                        "rcpps", Iop_RecipEst32Fx4 );
93640bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      goto decode_success;
93650bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
93660bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj
93670bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
93680bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
93690bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      vassert(sz == 4);
9370129b3d9da92af2ad2c58ffacb977aa5766211f08sewardj      delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
93711ddee21008ffdb2ac7f8e6a73445f150f753606fsewardj                                         "rcpss", Iop_RecipEst32F0x4 );
93720bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj      goto decode_success;
93730bd7ce6ae95b61bd9781f6a70f0132681a7b6387sewardj   }
9374b54520819b40c3fe907725b56bcd8db5112c0b9asewardj
9375c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
9376c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   if (insn[0] == 0x0F && insn[1] == 0x52) {
9377c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      vassert(sz == 4);
9378c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
93791ddee21008ffdb2ac7f8e6a73445f150f753606fsewardj                                        "rsqrtps", Iop_RSqrtEst32Fx4 );
9380c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9381c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9382c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9383c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
9384c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
9385c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      vassert(sz == 4);
9386c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
93871ddee21008ffdb2ac7f8e6a73445f150f753606fsewardj                                         "rsqrtss", Iop_RSqrtEst32F0x4 );
9388c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9389c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9390c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9391c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
9392008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
9393c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      Int    select;
9394c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      IRTemp sV, dV;
9395c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9396c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      sV = newTemp(Ity_V128);
9397c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      dV = newTemp(Ity_V128);
9398c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9399c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      modrm = insn[2];
9400c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
9401c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9402c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      if (epartIsReg(modrm)) {
9403c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
9404c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         select = (Int)insn[3];
9405c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         delta += 2+2;
9406c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         DIP("shufps $%d,%s,%s\n", select,
9407c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                   nameXMMReg(eregOfRM(modrm)),
9408c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                   nameXMMReg(gregOfRM(modrm)));
9409c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      } else {
9410c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9411c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9412c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         select = (Int)insn[2+alen];
9413c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         delta += 3+alen;
9414c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         DIP("shufps $%d,%s,%s\n", select,
9415c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                   dis_buf,
9416c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                   nameXMMReg(gregOfRM(modrm)));
9417c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      }
9418c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9419c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9420c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9421c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9422c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj#     define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
9423c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj#     define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9424c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9425c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      putXMMReg(
9426c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         gregOfRM(modrm),
9427c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
9428c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                       SELD((select>>2)&3), SELD((select>>0)&3) )
9429c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      );
9430c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9431c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj#     undef SELD
9432c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj#     undef SELS
9433c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9434c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9435c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9436c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9437c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
9438008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
9439c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9440c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                        "sqrtps", Iop_Sqrt32Fx4 );
9441c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9442c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9443c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9444c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9445c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
9446c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      vassert(sz == 4);
9447c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9448c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                         "sqrtss", Iop_Sqrt32F0x4 );
9449c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9450c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9451c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9452a0e83b06f304527e3e9aec527c344e35e7023d76sewardj   /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
94537df596b1e36840e2d74c90aa55589934add61ccfsewardj   if (insn[0] == 0x0F && insn[1] == 0xAE
94547df596b1e36840e2d74c90aa55589934add61ccfsewardj       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
94557df596b1e36840e2d74c90aa55589934add61ccfsewardj      modrm = getIByte(delta+2);
94567df596b1e36840e2d74c90aa55589934add61ccfsewardj      vassert(sz == 4);
94577df596b1e36840e2d74c90aa55589934add61ccfsewardj      vassert(!epartIsReg(modrm));
94587df596b1e36840e2d74c90aa55589934add61ccfsewardj
94597df596b1e36840e2d74c90aa55589934add61ccfsewardj      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
94607df596b1e36840e2d74c90aa55589934add61ccfsewardj      delta += 2+alen;
94617df596b1e36840e2d74c90aa55589934add61ccfsewardj
94627df596b1e36840e2d74c90aa55589934add61ccfsewardj      /* Fake up a native SSE mxcsr word.  The only thing it depends
94637df596b1e36840e2d74c90aa55589934add61ccfsewardj         on is SSEROUND[1:0], so call a clean helper to cook it up.
94647df596b1e36840e2d74c90aa55589934add61ccfsewardj      */
94657df596b1e36840e2d74c90aa55589934add61ccfsewardj      /* UInt x86h_create_mxcsr ( UInt sseround ) */
946633dd31b1bcc175495b96222fa278062fd6116899sewardj      DIP("stmxcsr %s\n", dis_buf);
94677df596b1e36840e2d74c90aa55589934add61ccfsewardj      storeLE( mkexpr(addr),
94687df596b1e36840e2d74c90aa55589934add61ccfsewardj               mkIRExprCCall(
94697df596b1e36840e2d74c90aa55589934add61ccfsewardj                  Ity_I32, 0/*regp*/,
94703bd6f3ee3f38fe11f302dd41b2781c7bbc0f201csewardj                  "x86g_create_mxcsr", &x86g_create_mxcsr,
9471a0e83b06f304527e3e9aec527c344e35e7023d76sewardj                  mkIRExprVec_1( get_sse_roundingmode() )
94727df596b1e36840e2d74c90aa55589934add61ccfsewardj               )
94737df596b1e36840e2d74c90aa55589934add61ccfsewardj             );
94747df596b1e36840e2d74c90aa55589934add61ccfsewardj      goto decode_success;
94757df596b1e36840e2d74c90aa55589934add61ccfsewardj   }
94767df596b1e36840e2d74c90aa55589934add61ccfsewardj
9477c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
9478008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
9479c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
9480c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9481c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9482c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9483008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
9484c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
9485c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      vassert(sz == 4);
9486c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
9487c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9488c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9489c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9490c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9491c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9492c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* These just appear to be special cases of SHUFPS */
9493008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9494c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      IRTemp sV, dV;
9495c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
94962d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool hi = toBool(insn[1] == 0x15);
9497c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      sV = newTemp(Ity_V128);
9498c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      dV = newTemp(Ity_V128);
9499c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9500c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      modrm = insn[2];
9501c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
9502c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9503c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      if (epartIsReg(modrm)) {
9504c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
9505c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         delta += 2+1;
9506c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9507c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                  nameXMMReg(eregOfRM(modrm)),
9508c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                  nameXMMReg(gregOfRM(modrm)));
9509c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      } else {
9510c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9511c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9512c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         delta += 2+alen;
9513c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9514c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                  dis_buf,
9515c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj                                  nameXMMReg(gregOfRM(modrm)));
9516c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      }
9517c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9518c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9519c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9520c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9521c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      if (hi) {
9522c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
9523c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      } else {
9524c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj         putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
9525c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      }
9526c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9527c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9528c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9529c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9530c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   /* 0F 57 = XORPS -- G = G and E */
9531008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
9532f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_XorV128 );
9533c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj      goto decode_success;
9534c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj   }
9535c1e7dfc9370ee70f7e9f52294c764d4233619927sewardj
9536636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* ---------------------------------------------------- */
9537636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* --- end of the SSE decoder.                      --- */
9538636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* ---------------------------------------------------- */
9539636ad762e49597ef608323f27c7b8eb66962cd90sewardj
9540636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* ---------------------------------------------------- */
9541636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* --- start of the SSE2 decoder.                   --- */
9542636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* ---------------------------------------------------- */
9543636ad762e49597ef608323f27c7b8eb66962cd90sewardj
95449df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj   /* Skip parts of the decoder which don't apply given the stated
95459df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj      guest subarchitecture. */
95465117ce116f47141cb23d1b49cc826e19323add97sewardj   if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
95475117ce116f47141cb23d1b49cc826e19323add97sewardj      goto after_sse_decoders; /* no SSE2 capabilities */
95489df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj
95498462d113e3efeacceb304222dada8d85f748295aflorian   insn = &guest_code[delta];
9550636ad762e49597ef608323f27c7b8eb66962cd90sewardj
9551636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9552636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
9553636ad762e49597ef608323f27c7b8eb66962cd90sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
9554636ad762e49597ef608323f27c7b8eb66962cd90sewardj      goto decode_success;
9555636ad762e49597ef608323f27c7b8eb66962cd90sewardj   }
9556636ad762e49597ef608323f27c7b8eb66962cd90sewardj
9557636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9558636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
9559636ad762e49597ef608323f27c7b8eb66962cd90sewardj      vassert(sz == 4);
9560636ad762e49597ef608323f27c7b8eb66962cd90sewardj      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
9561636ad762e49597ef608323f27c7b8eb66962cd90sewardj      goto decode_success;
9562636ad762e49597ef608323f27c7b8eb66962cd90sewardj   }
9563636ad762e49597ef608323f27c7b8eb66962cd90sewardj
9564636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9565636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
9566f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_AndV128 );
9567636ad762e49597ef608323f27c7b8eb66962cd90sewardj      goto decode_success;
9568636ad762e49597ef608323f27c7b8eb66962cd90sewardj   }
9569636ad762e49597ef608323f27c7b8eb66962cd90sewardj
9570636ad762e49597ef608323f27c7b8eb66962cd90sewardj   /* 66 0F 54 = ANDPD -- G = G and E */
9571636ad762e49597ef608323f27c7b8eb66962cd90sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
9572f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_AndV128 );
9573636ad762e49597ef608323f27c7b8eb66962cd90sewardj      goto decode_success;
9574636ad762e49597ef608323f27c7b8eb66962cd90sewardj   }
9575636ad762e49597ef608323f27c7b8eb66962cd90sewardj
9576fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9577fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
9578fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
9579fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9580fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9581fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9582fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9583fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
9584fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
9585fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
9586fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9587fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9588fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9589fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 2F = COMISD  -- 64F0x2 comparison G,E, and set ZCP */
9590fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
9591fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9592fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argL = newTemp(Ity_F64);
9593fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argR = newTemp(Ity_F64);
9594fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9595fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9596fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
9597fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9598fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9599fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                  nameXMMReg(gregOfRM(modrm)) );
9600fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9601fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9602fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9603fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9604fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("[u]comisd %s,%s\n", dis_buf,
9605fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                  nameXMMReg(gregOfRM(modrm)) );
9606fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9607fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
9608fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9609fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
9610fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
9611fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      stmt( IRStmt_Put(
9612fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj               OFFB_CC_DEP1,
9613fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj               binop( Iop_And32,
9614fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                      binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
9615fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                      mkU32(0x45)
9616fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj          )));
9617a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      /* Set NDEP even though it isn't used.  This makes redundant-PUT
9618a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj         elimination of previous stores to this field work better. */
9619a3b7e3a75bf54428322039d7efddbbc210c56c01sewardj      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
9620fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9621fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9622fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9623fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9624fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      F64 in xmm(G) */
9625fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
9626fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp arg64 = newTemp(Ity_I64);
9627fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
9628fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9629fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
9630fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9631fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
9632fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
9633fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9634fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9635fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9636fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9637fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9638fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
9639fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtdq2pd %s,%s\n", dis_buf,
9640fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9641fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9642fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9643fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F(
9644fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         gregOfRM(modrm), 0,
96456c299f3acab617581ea504e45fbb6cab24c2b29fsewardj         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)))
9646fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      );
9647fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9648fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F(
9649fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         gregOfRM(modrm), 1,
96506c299f3acab617581ea504e45fbb6cab24c2b29fsewardj         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)))
9651fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      );
9652fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9653fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9654fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9655fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9656fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9657fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      xmm(G) */
9658fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
9659fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argV  = newTemp(Ity_V128);
9660fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
9661fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9662fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9663fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9664fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argV, getXMMReg(eregOfRM(modrm)) );
9665fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9666fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9667fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9668fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9669fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9670fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9671fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9672fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtdq2ps %s,%s\n", dis_buf,
9673fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9674fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9675fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9676fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, get_sse_roundingmode() );
9677fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9678fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9679fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     define CVT(_t)  binop( Iop_F64toF32,                    \
9680fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(rmode),                   \
96816c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                             unop(Iop_I32StoF64,mkexpr(_t)))
9682fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9683fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
9684fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
9685fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9686fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9687fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9688fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     undef CVT
9689fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9690fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9691fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9692fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9693fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9694fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      lo half xmm(G), and zero upper half */
9695fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
9696fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argV  = newTemp(Ity_V128);
9697fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
9698fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
9699fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9700fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
9701fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9702fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argV, getXMMReg(eregOfRM(modrm)) );
9703fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
9704fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9705fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9706fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9707fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9708fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9709fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
9710fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtpd2dq %s,%s\n", dis_buf,
9711fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9712fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9713fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9714fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, get_sse_roundingmode() );
9715fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      t0 = newTemp(Ity_F64);
9716fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      t1 = newTemp(Ity_F64);
9717fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( t0, unop(Iop_ReinterpI64asF64,
9718f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                       unop(Iop_V128to64, mkexpr(argV))) );
9719fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( t1, unop(Iop_ReinterpI64asF64,
9720f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                       unop(Iop_V128HIto64, mkexpr(argV))) );
9721fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
97226c299f3acab617581ea504e45fbb6cab24c2b29fsewardj#     define CVT(_t)  binop( Iop_F64toI32S,                   \
9723fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(rmode),                   \
9724fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(_t) )
9725fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9726fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9727fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9728fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9729fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9730fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9731fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     undef CVT
9732fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9733fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9734fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9735fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9736fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9737fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      I32 in mmx, according to prevailing SSE rounding mode */
9738fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9739fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      I32 in mmx, rounding towards zero */
9740fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9741fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp dst64  = newTemp(Ity_I64);
9742fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode  = newTemp(Ity_I32);
9743fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f64lo  = newTemp(Ity_F64);
9744fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f64hi  = newTemp(Ity_F64);
97452d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool   r2zero = toBool(insn[1] == 0x2C);
9746fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9747fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      do_MMX_preamble();
9748fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9749fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9750fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9751fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9752fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9753fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
9754fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9755fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   nameXMMReg(eregOfRM(modrm)),
9756fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   nameMMXReg(gregOfRM(modrm)));
9757fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9758fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9759fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9760fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
9761fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                              mkexpr(addr),
9762fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                              mkU32(8) )));
9763fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9764fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9765fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   dis_buf,
9766fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   nameMMXReg(gregOfRM(modrm)));
9767fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9768fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9769fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (r2zero) {
9770fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign(rmode, mkU32((UInt)Irrm_ZERO) );
9771fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9772fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( rmode, get_sse_roundingmode() );
9773fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9774fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9775fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign(
9776fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         dst64,
9777fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         binop( Iop_32HLto64,
97786c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64hi) ),
97796c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo) )
9780fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj              )
9781fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      );
9782fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9783fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putMMXReg(gregOfRM(modrm), mkexpr(dst64));
9784fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9785fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9786fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9787fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9788fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      lo half xmm(G), and zero upper half */
9789fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* Note, this is practically identical to CVTPD2DQ.  It would have
9790fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      been nicer to merge them together, but the insn[] offsets differ
9791fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      by one. */
9792fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
9793fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argV  = newTemp(Ity_V128);
9794fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
9795fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9796fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9797fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9798fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argV, getXMMReg(eregOfRM(modrm)) );
9799fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9800fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9801fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9802fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9803fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9804fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9805fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9806fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtpd2ps %s,%s\n", dis_buf,
9807fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9808fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9809fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9810fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, get_sse_roundingmode() );
9811fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      t0 = newTemp(Ity_F64);
9812fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      t1 = newTemp(Ity_F64);
9813fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( t0, unop(Iop_ReinterpI64asF64,
9814f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                       unop(Iop_V128to64, mkexpr(argV))) );
9815fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( t1, unop(Iop_ReinterpI64asF64,
9816f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                       unop(Iop_V128HIto64, mkexpr(argV))) );
9817fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9818fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     define CVT(_t)  binop( Iop_F64toF32,                    \
9819fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(rmode),                   \
9820fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(_t) )
9821fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9822fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32(  gregOfRM(modrm), 3, mkU32(0) );
9823fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32(  gregOfRM(modrm), 2, mkU32(0) );
9824fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9825fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9826fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9827fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     undef CVT
9828fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9829fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9830fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9831fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9832fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9833fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      xmm(G) */
9834fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
9835fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp arg64 = newTemp(Ity_I64);
9836fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9837fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9838fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
983930a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj         /* Only switch to MMX mode if the source is a MMX register.
984030a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj            This is inconsistent with all other instructions which
984130a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj            convert between XMM and (M64 or MMX), which always switch
984230a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj            to MMX mode even if 64-bit operand is M64 and not MMX.  At
984330a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj            least, that's what the Intel docs seem to me to say.
984430a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj            Fixes #210264. */
984530a20e9ebf9158d86f9f61351d8f00f610273ee8sewardj         do_MMX_preamble();
9846fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( arg64, getMMXReg(eregOfRM(modrm)) );
9847fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9848fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9849fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9850fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9851fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9852fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9853fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9854fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtpi2pd %s,%s\n", dis_buf,
9855fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9856fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9857fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9858fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F(
9859fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         gregOfRM(modrm), 0,
98606c299f3acab617581ea504e45fbb6cab24c2b29fsewardj         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)) )
9861fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      );
9862fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9863fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F(
9864fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         gregOfRM(modrm), 1,
98656c299f3acab617581ea504e45fbb6cab24c2b29fsewardj         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)) )
9866fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      );
9867fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9868fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9869fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9870fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9871fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9872fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      xmm(G) */
9873fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
9874fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argV  = newTemp(Ity_V128);
9875fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
9876fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9877fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9878fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9879fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argV, getXMMReg(eregOfRM(modrm)) );
9880fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9881fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9882fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9883fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9884fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9885fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9886fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9887fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtps2dq %s,%s\n", dis_buf,
9888fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9889fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9890fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9891fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, get_sse_roundingmode() );
9892fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9893fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9894fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      /* This is less than ideal.  If it turns out to be a performance
9895fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 bottleneck it can be improved. */
9896fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     define CVT(_t)                            \
98976c299f3acab617581ea504e45fbb6cab24c2b29fsewardj        binop( Iop_F64toI32S,                   \
9898fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj               mkexpr(rmode),                   \
9899fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj               unop( Iop_F32toF64,              \
9900fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                     unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9901fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9902fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9903fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9904fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9905fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9906fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9907fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     undef CVT
9908fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9909fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9910fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9911fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9912fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9913fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      F64 in xmm(G). */
9914fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
9915fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f32lo = newTemp(Ity_F32);
9916fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f32hi = newTemp(Ity_F32);
9917fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9918fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
9919fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9920fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
9921fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
9922fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
9923fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9924fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9925fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9926fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9927fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9928fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( f32hi, loadLE(Ity_F32,
9929fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                               binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
9930fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
9931fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtps2pd %s,%s\n", dis_buf,
9932fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
9933fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9934fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9935fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F( gregOfRM(modrm), 1,
9936fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                        unop(Iop_F32toF64, mkexpr(f32hi)) );
9937fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F( gregOfRM(modrm), 0,
9938fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                        unop(Iop_F32toF64, mkexpr(f32lo)) );
9939fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9940fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9941fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9942fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9943fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
9944fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      I32 in ireg, according to prevailing SSE rounding mode */
9945fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
99460b21044f0cbfd84788247ed7ba65cf77ea832a2csewardj      I32 in ireg, rounding towards zero */
9947fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F
9948fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj       && (insn[2] == 0x2D || insn[2] == 0x2C)) {
9949fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
9950fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f64lo = newTemp(Ity_F64);
99512d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool   r2zero = toBool(insn[2] == 0x2C);
9952fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
9953fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9954fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
9955fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9956fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
9957fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9958fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9959fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   nameXMMReg(eregOfRM(modrm)),
9960fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   nameIReg(4, gregOfRM(modrm)));
9961fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9962fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9963fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9964fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
9965fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9966fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   dis_buf,
9967fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                   nameIReg(4, gregOfRM(modrm)));
9968fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9969fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9970fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (r2zero) {
9971fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( rmode, mkU32((UInt)Irrm_ZERO) );
9972fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9973fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( rmode, get_sse_roundingmode() );
9974fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
9975fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9976fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putIReg(4, gregOfRM(modrm),
99776c299f3acab617581ea504e45fbb6cab24c2b29fsewardj                 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo)) );
9978fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9979fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
9980fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
9981fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9982fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
9983fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      low 1/4 xmm(G), according to prevailing SSE rounding mode */
9984fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
9985fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
9986fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f64lo = newTemp(Ity_F64);
9987fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
9988fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
9989fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
9990fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
9991fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
9992fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9993fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9994fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
9995fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
9996fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9997fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9998fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
9999fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtsd2ss %s,%s\n", dis_buf,
10000fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
10001fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
10002fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10003fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, get_sse_roundingmode() );
10004fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32F(
10005fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         gregOfRM(modrm), 0,
10006fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
10007fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      );
10008fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10009fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
10010fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
10011fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10012fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
10013fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      half xmm */
10014fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
10015fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp arg32 = newTemp(Ity_I32);
10016fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
10017fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10018fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
10019fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
10020fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( arg32, getIReg(4, eregOfRM(modrm)) );
10021fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
10022fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
10023fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
10024fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
10025fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10026fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
10027fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
10028fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtsi2sd %s,%s\n", dis_buf,
10029fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)) );
10030fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
10031fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10032fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F(
10033fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         gregOfRM(modrm), 0,
100346c299f3acab617581ea504e45fbb6cab24c2b29fsewardj         unop(Iop_I32StoF64, mkexpr(arg32)) );
10035fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10036fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
10037fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
10038fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10039fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
10040fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      low half xmm(G) */
10041fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
10042fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp f32lo = newTemp(Ity_F32);
10043fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
10044fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10045fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
10046fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
10047fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
10048fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
10049fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10050fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
10051fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
10052fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10053fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
10054fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
10055fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvtss2sd %s,%s\n", dis_buf,
10056fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                 nameXMMReg(gregOfRM(modrm)));
10057fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
10058fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10059fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane64F( gregOfRM(modrm), 0,
10060fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                        unop( Iop_F32toF64, mkexpr(f32lo) ) );
10061fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10062fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
10063fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
10064fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10065fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
10066fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      lo half xmm(G), and zero upper half, rounding towards zero */
10067fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
10068fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argV  = newTemp(Ity_V128);
10069fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
10070fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10071fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+2);
10072fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
10073fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argV, getXMMReg(eregOfRM(modrm)) );
10074fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+1;
10075fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10076fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                  nameXMMReg(gregOfRM(modrm)));
10077fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
10078fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10079fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10080fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 2+alen;
10081fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvttpd2dq %s,%s\n", dis_buf,
10082fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                  nameXMMReg(gregOfRM(modrm)) );
10083fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
10084fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10085fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, mkU32((UInt)Irrm_ZERO) );
10086fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10087fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      t0 = newTemp(Ity_F64);
10088fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      t1 = newTemp(Ity_F64);
10089fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( t0, unop(Iop_ReinterpI64asF64,
10090f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                       unop(Iop_V128to64, mkexpr(argV))) );
10091fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( t1, unop(Iop_ReinterpI64asF64,
10092f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                       unop(Iop_V128HIto64, mkexpr(argV))) );
10093fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
100946c299f3acab617581ea504e45fbb6cab24c2b29fsewardj#     define CVT(_t)  binop( Iop_F64toI32S,                   \
10095fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(rmode),                   \
10096fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                             mkexpr(_t) )
10097fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10098fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
10099fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
10100fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
10101fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
10102fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10103fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     undef CVT
10104fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10105fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
10106fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
10107fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10108fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
10109fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      xmm(G), rounding towards zero */
10110fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
10111fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp argV  = newTemp(Ity_V128);
10112fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      IRTemp rmode = newTemp(Ity_I32);
10113fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      vassert(sz == 4);
10114fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10115fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      modrm = getIByte(delta+3);
10116fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      if (epartIsReg(modrm)) {
10117fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         assign( argV, getXMMReg(eregOfRM(modrm)) );
10118fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+1;
10119fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10120fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                  nameXMMReg(gregOfRM(modrm)));
10121fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      } else {
10122fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10123fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10124fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         delta += 3+alen;
10125fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj         DIP("cvttps2dq %s,%s\n", dis_buf,
10126fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                                  nameXMMReg(gregOfRM(modrm)) );
10127fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      }
10128fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10129fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      assign( rmode, mkU32((UInt)Irrm_ZERO) );
10130fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
10131fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10132fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      /* This is less than ideal.  If it turns out to be a performance
10133fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj	 bottleneck it can be improved. */
10134fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     define CVT(_t)                            \
101356c299f3acab617581ea504e45fbb6cab24c2b29fsewardj        binop( Iop_F64toI32S,                   \
10136fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj               mkexpr(rmode),                   \
10137fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj               unop( Iop_F32toF64,              \
10138fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj                     unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
10139fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10140fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
10141fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
10142fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
10143fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
10144fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10145fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj#     undef CVT
10146fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10147fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
10148fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
10149fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10150fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
10151fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
10152fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
10153fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj      goto decode_success;
10154fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj   }
10155fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10156c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
10157c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5E) {
10158c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10159c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "divsd", Iop_Div64F0x2 );
10160c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10161c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10162c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10163c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 0F AE /5 = LFENCE -- flush pending operations to memory */
10164c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 0F AE /6 = MFENCE -- flush pending operations to memory */
10165c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0x0F && insn[1] == 0xAE
10166c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj       && epartIsReg(insn[2])
10167c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj       && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
10168c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10169c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      delta += 3;
101703e83893fff6c7bbc955d4529cd922df4ed9b23cdsewardj      /* Insert a memory fence.  It's sometimes important that these
101713e83893fff6c7bbc955d4529cd922df4ed9b23cdsewardj         are carried through to the generated code. */
10172c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj      stmt( IRStmt_MBE(Imbe_Fence) );
10173c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
10174c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10175c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10176c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10177c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
10178c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
10179c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
10180c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10181c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10182c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10183c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
10184c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5F) {
10185c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10186c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "maxsd", Iop_Max64F0x2 );
10187c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10188c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10189c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10190c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
10191c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
10192c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
10193c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10194c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10195c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10196c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
10197c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) {
10198c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10199c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 );
10200c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10201c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10202c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10203c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
10204c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
10205c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
10206c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F
10207c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj       && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
1020855085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* wot = insn[1]==0x28 ? "apd" :
1020955085f8680acc89d727e321f3b34cae1a8c4093aflorian                         insn[1]==0x10 ? "upd" : "dqa";
10210c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10211c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10212c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( gregOfRM(modrm),
10213c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    getXMMReg( eregOfRM(modrm) ));
10214c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)),
10215c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                   nameXMMReg(gregOfRM(modrm)));
10216c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+1;
10217c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10218c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
1021945ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj         if (insn[1] == 0x28/*movapd*/ || insn[1] == 0x6F/*movdqa*/)
1022045ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj            gen_SEGV_if_not_16_aligned( addr );
10221c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( gregOfRM(modrm),
10222c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    loadLE(Ity_V128, mkexpr(addr)) );
10223c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("mov%s %s,%s\n", wot, dis_buf,
10224c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                   nameXMMReg(gregOfRM(modrm)));
10225c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10226c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10227c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10228c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10229c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
1023095535feeb27c5641608bc9eb83c047837281a7f4sewardj   /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
102311c31877a29646fb6f902de217ae8f62bccfeda7dsewardj   /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
102321c31877a29646fb6f902de217ae8f62bccfeda7dsewardj   if (sz == 2 && insn[0] == 0x0F
102331c31877a29646fb6f902de217ae8f62bccfeda7dsewardj       && (insn[1] == 0x29 || insn[1] == 0x11)) {
1023455085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* wot = insn[1]==0x29 ? "apd" : "upd";
1023595535feeb27c5641608bc9eb83c047837281a7f4sewardj      modrm = getIByte(delta+2);
1023695535feeb27c5641608bc9eb83c047837281a7f4sewardj      if (epartIsReg(modrm)) {
1023795535feeb27c5641608bc9eb83c047837281a7f4sewardj         /* fall through; awaiting test case */
1023895535feeb27c5641608bc9eb83c047837281a7f4sewardj      } else {
1023995535feeb27c5641608bc9eb83c047837281a7f4sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
1024045ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj         if (insn[1] == 0x29/*movapd*/)
1024145ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj            gen_SEGV_if_not_16_aligned( addr );
1024295535feeb27c5641608bc9eb83c047837281a7f4sewardj         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
102431c31877a29646fb6f902de217ae8f62bccfeda7dsewardj         DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRM(modrm)),
102441c31877a29646fb6f902de217ae8f62bccfeda7dsewardj                                   dis_buf );
1024595535feeb27c5641608bc9eb83c047837281a7f4sewardj         delta += 2+alen;
1024695535feeb27c5641608bc9eb83c047837281a7f4sewardj         goto decode_success;
1024795535feeb27c5641608bc9eb83c047837281a7f4sewardj      }
1024895535feeb27c5641608bc9eb83c047837281a7f4sewardj   }
1024995535feeb27c5641608bc9eb83c047837281a7f4sewardj
10250c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
10251c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
10252c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10253c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10254c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+1;
10255c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg(
10256c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj            gregOfRM(modrm),
10257f0c1c58d6e47608ce166058997f795f1d7d45127sewardj            unop( Iop_32UtoV128, getIReg(4, eregOfRM(modrm)) )
10258c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         );
10259c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movd %s, %s\n",
10260c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj             nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
10261c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10262c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode( &alen, sorb, delta+2, dis_buf );
10263c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10264c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg(
10265c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj            gregOfRM(modrm),
10266f0c1c58d6e47608ce166058997f795f1d7d45127sewardj            unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
10267c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         );
10268c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
10269c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10270c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10271c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10272c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10273c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
10274c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
10275c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10276c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10277c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+1;
10278c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putIReg( 4, eregOfRM(modrm),
10279c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                  getXMMRegLane32(gregOfRM(modrm), 0) );
10280c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movd %s, %s\n",
10281c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj             nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
10282c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10283c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode( &alen, sorb, delta+2, dis_buf );
10284c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10285c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr),
10286c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                  getXMMRegLane32(gregOfRM(modrm), 0) );
10287c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10288c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10289c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10290c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10291c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10292c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
10293c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
10294c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10295c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10296c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+1;
10297c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( eregOfRM(modrm),
10298c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    getXMMReg(gregOfRM(modrm)) );
10299c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10300c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                nameXMMReg(eregOfRM(modrm)));
10301c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10302c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode( &alen, sorb, delta+2, dis_buf );
10303c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
1030445ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj         gen_SEGV_if_not_16_aligned( addr );
10305c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10306c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10307c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10308c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10309c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10310c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10311c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
10312c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* Unfortunately can't simply use the MOVDQA case since the
10313c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      prefix lengths are different (66 vs F3) */
10314c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
10315c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10316c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+3);
10317c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10318c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( gregOfRM(modrm),
10319c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    getXMMReg( eregOfRM(modrm) ));
10320c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10321c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                               nameXMMReg(gregOfRM(modrm)));
10322c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+1;
10323c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10324c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10325c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( gregOfRM(modrm),
10326c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    loadLE(Ity_V128, mkexpr(addr)) );
10327c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdqu %s,%s\n", dis_buf,
10328c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                               nameXMMReg(gregOfRM(modrm)));
10329c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+alen;
10330c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10331c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10332c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10333c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10334c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
10335c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* Unfortunately can't simply use the MOVDQA case since the
10336c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      prefix lengths are different (66 vs F3) */
10337c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
10338c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10339c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+3);
10340c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10341c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+1;
10342c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( eregOfRM(modrm),
10343c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    getXMMReg(gregOfRM(modrm)) );
10344c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10345c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                nameXMMReg(eregOfRM(modrm)));
10346c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10347c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode( &alen, sorb, delta+3, dis_buf );
10348c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+alen;
10349c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10350c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10351c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10352c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10353c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10354c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10355c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
10356c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
10357c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10358c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+3);
10359c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10360c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         do_MMX_preamble();
10361c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putMMXReg( gregOfRM(modrm),
10362c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    getXMMRegLane64( eregOfRM(modrm), 0 ));
10363c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10364c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                nameMMXReg(gregOfRM(modrm)));
10365c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+1;
10366c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10367c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10368c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         /* fall through, apparently no mem case for this insn */
10369c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10370c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10371c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10372c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
10373c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* These seems identical to MOVHPS.  This instruction encoding is
10374c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      completely crazy. */
10375c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
10376c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10377c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10378c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         /* fall through; apparently reg-reg is not possible */
10379c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10380c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10381c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10382c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
10383c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                          loadLE(Ity_I64, mkexpr(addr)) );
10384c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movhpd %s,%s\n", dis_buf,
10385c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                               nameXMMReg( gregOfRM(modrm) ));
10386c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10387c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10388c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10389c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10390c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
10391c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* Again, this seems identical to MOVHPS. */
10392c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
10393c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (!epartIsReg(insn[2])) {
10394c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2;
10395c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta, dis_buf );
10396c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += alen;
10397c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr),
10398c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                  getXMMRegLane64( gregOfRM(insn[2]),
10399c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                   1/*upper lane*/ ) );
10400c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
10401c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                               dis_buf);
10402c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10403c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10404c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      /* else fall through */
10405c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10406c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10407c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
10408c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* Identical to MOVLPS ? */
10409c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x12) {
10410c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10411c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10412c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         /* fall through; apparently reg-reg is not possible */
10413c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10414c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10415c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10416c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMRegLane64( gregOfRM(modrm),  0/*lower lane*/,
10417c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                          loadLE(Ity_I64, mkexpr(addr)) );
10418c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movlpd %s, %s\n",
10419c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj             dis_buf, nameXMMReg( gregOfRM(modrm) ));
10420c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10421c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10422c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10423c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10424c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
10425c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* Identical to MOVLPS ? */
10426c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
10427c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (!epartIsReg(insn[2])) {
10428c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2;
10429c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta, dis_buf );
10430c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += alen;
10431c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr),
10432c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                  getXMMRegLane64( gregOfRM(insn[2]),
10433c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                   0/*lower lane*/ ) );
10434c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
10435c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                dis_buf);
10436c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10437c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10438c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      /* else fall through */
10439c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10440c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10441c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10442c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      2 lowest bits of ireg(G) */
10443c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0x0F && insn[1] == 0x50) {
10444c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10445c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (sz == 2 && epartIsReg(modrm)) {
10446c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         Int src;
10447c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         t0 = newTemp(Ity_I32);
10448c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         t1 = newTemp(Ity_I32);
10449c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+1;
10450c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         src = eregOfRM(modrm);
10451c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         assign( t0, binop( Iop_And32,
10452c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                            binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10453c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                            mkU32(1) ));
10454c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         assign( t1, binop( Iop_And32,
10455c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                            binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10456c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                            mkU32(2) ));
10457c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putIReg(4, gregOfRM(modrm),
10458c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                    binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10459c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                 );
10460c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movmskpd %s,%s\n", nameXMMReg(src),
10461c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                 nameIReg(4, gregOfRM(modrm)));
10462c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10463c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10464c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      /* else fall through */
10465c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10466c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10467d71ba837242cc470f622335b1c650bce8886a533sewardj   /* 66 0F F7 = MASKMOVDQU -- store selected bytes of double quadword */
10468d71ba837242cc470f622335b1c650bce8886a533sewardj   if (insn[0] == 0x0F && insn[1] == 0xF7) {
10469d71ba837242cc470f622335b1c650bce8886a533sewardj      modrm = getIByte(delta+2);
10470d71ba837242cc470f622335b1c650bce8886a533sewardj      if (sz == 2 && epartIsReg(modrm)) {
10471d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp regD    = newTemp(Ity_V128);
10472d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp mask    = newTemp(Ity_V128);
10473d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp olddata = newTemp(Ity_V128);
10474d71ba837242cc470f622335b1c650bce8886a533sewardj         IRTemp newdata = newTemp(Ity_V128);
10475d71ba837242cc470f622335b1c650bce8886a533sewardj                addr    = newTemp(Ity_I32);
10476d71ba837242cc470f622335b1c650bce8886a533sewardj
10477d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
10478d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( regD, getXMMReg( gregOfRM(modrm) ));
10479d71ba837242cc470f622335b1c650bce8886a533sewardj
10480d71ba837242cc470f622335b1c650bce8886a533sewardj         /* Unfortunately can't do the obvious thing with SarN8x16
10481d71ba837242cc470f622335b1c650bce8886a533sewardj            here since that can't be re-emitted as SSE2 code - no such
10482d71ba837242cc470f622335b1c650bce8886a533sewardj            insn. */
10483d71ba837242cc470f622335b1c650bce8886a533sewardj	 assign(
10484d71ba837242cc470f622335b1c650bce8886a533sewardj            mask,
10485d71ba837242cc470f622335b1c650bce8886a533sewardj            binop(Iop_64HLtoV128,
10486d71ba837242cc470f622335b1c650bce8886a533sewardj                  binop(Iop_SarN8x8,
10487d71ba837242cc470f622335b1c650bce8886a533sewardj                        getXMMRegLane64( eregOfRM(modrm), 1 ),
10488d71ba837242cc470f622335b1c650bce8886a533sewardj                        mkU8(7) ),
10489d71ba837242cc470f622335b1c650bce8886a533sewardj                  binop(Iop_SarN8x8,
10490d71ba837242cc470f622335b1c650bce8886a533sewardj                        getXMMRegLane64( eregOfRM(modrm), 0 ),
10491d71ba837242cc470f622335b1c650bce8886a533sewardj                        mkU8(7) ) ));
10492d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( olddata, loadLE( Ity_V128, mkexpr(addr) ));
10493d71ba837242cc470f622335b1c650bce8886a533sewardj         assign( newdata,
10494d71ba837242cc470f622335b1c650bce8886a533sewardj                 binop(Iop_OrV128,
10495d71ba837242cc470f622335b1c650bce8886a533sewardj                       binop(Iop_AndV128,
10496d71ba837242cc470f622335b1c650bce8886a533sewardj                             mkexpr(regD),
10497d71ba837242cc470f622335b1c650bce8886a533sewardj                             mkexpr(mask) ),
10498d71ba837242cc470f622335b1c650bce8886a533sewardj                       binop(Iop_AndV128,
10499d71ba837242cc470f622335b1c650bce8886a533sewardj                             mkexpr(olddata),
10500d71ba837242cc470f622335b1c650bce8886a533sewardj                             unop(Iop_NotV128, mkexpr(mask)))) );
10501d71ba837242cc470f622335b1c650bce8886a533sewardj         storeLE( mkexpr(addr), mkexpr(newdata) );
10502d71ba837242cc470f622335b1c650bce8886a533sewardj
10503d71ba837242cc470f622335b1c650bce8886a533sewardj         delta += 2+1;
10504d71ba837242cc470f622335b1c650bce8886a533sewardj         DIP("maskmovdqu %s,%s\n", nameXMMReg( eregOfRM(modrm) ),
10505d71ba837242cc470f622335b1c650bce8886a533sewardj                                   nameXMMReg( gregOfRM(modrm) ) );
10506d71ba837242cc470f622335b1c650bce8886a533sewardj         goto decode_success;
10507d71ba837242cc470f622335b1c650bce8886a533sewardj      }
10508d71ba837242cc470f622335b1c650bce8886a533sewardj      /* else fall through */
10509d71ba837242cc470f622335b1c650bce8886a533sewardj   }
10510d71ba837242cc470f622335b1c650bce8886a533sewardj
10511c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10512c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0x0F && insn[1] == 0xE7) {
10513c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10514c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (sz == 2 && !epartIsReg(modrm)) {
10515c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
1051645ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj         gen_SEGV_if_not_16_aligned( addr );
10517c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10518c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movntdq %s,%s\n", dis_buf,
10519c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                nameXMMReg(gregOfRM(modrm)));
10520c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10521c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10522c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10523c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      /* else fall through */
10524c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10525c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10526c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10527c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0x0F && insn[1] == 0xC3) {
10528c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10529c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+2);
10530c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (!epartIsReg(modrm)) {
10531c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10532c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
10533c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movnti %s,%s\n", dis_buf,
10534c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                               nameIReg(4, gregOfRM(modrm)));
10535c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 2+alen;
10536c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10537c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10538c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      /* else fall through */
10539c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10540c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
1054195535feeb27c5641608bc9eb83c047837281a7f4sewardj   /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
1054295535feeb27c5641608bc9eb83c047837281a7f4sewardj      or lo half xmm).  */
105439ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
105449ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      modrm = getIByte(delta+2);
105459ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      if (epartIsReg(modrm)) {
105469ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj         /* fall through, awaiting test case */
105476d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj         /* dst: lo half copied, hi half zeroed */
105489ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      } else {
105499ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
105509ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj         storeLE( mkexpr(addr),
105519ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj                  getXMMRegLane64( gregOfRM(modrm), 0 ));
105529ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj         DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
105539ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj         delta += 2+alen;
105549ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj         goto decode_success;
105559ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      }
105569ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj   }
105579ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj
10558c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10559c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      hi half). */
10560c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
10561c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10562c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+3);
10563c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10564c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         do_MMX_preamble();
10565c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMReg( gregOfRM(modrm),
10566f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                    unop(Iop_64UtoV128, getMMXReg( eregOfRM(modrm) )) );
10567c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10568c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                                nameXMMReg(gregOfRM(modrm)));
10569c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+1;
10570c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         goto decode_success;
10571c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10572c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         /* fall through, apparently no mem case for this insn */
10573c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10574c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10575c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
1057695535feeb27c5641608bc9eb83c047837281a7f4sewardj   /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
105776d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj      G (lo half xmm).  Upper half of G is zeroed out. */
1057895535feeb27c5641608bc9eb83c047837281a7f4sewardj   /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
1057995535feeb27c5641608bc9eb83c047837281a7f4sewardj      G (lo half xmm).  If E is mem, upper half of G is zeroed out.
105806d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj      If E is reg, upper half of G is unchanged. */
1058195535feeb27c5641608bc9eb83c047837281a7f4sewardj   if ((insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x10)
1058295535feeb27c5641608bc9eb83c047837281a7f4sewardj       || (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7E)) {
10583c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10584c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+3);
10585c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10586c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMRegLane64( gregOfRM(modrm), 0,
10587c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                          getXMMRegLane64( eregOfRM(modrm), 0 ));
105886d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj         if (insn[0] == 0xF3/*MOVQ*/) {
105896d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj            /* zero bits 127:64 */
105906d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj            putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
105916d7ccd58985bbbee93307c35fdc44a112e5ae746sewardj         }
10592c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movsd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10593c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                              nameXMMReg(gregOfRM(modrm)));
10594c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+1;
10595c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10596c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10597ad50db03b717271467900b0616bc9e6c492f063dsewardj         /* zero bits 127:64 */
105985bf1fd45a1db0c7f2f51af6e1be3849b01a40e9esewardj         putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
10599ad50db03b717271467900b0616bc9e6c492f063dsewardj         /* write bits 63:0 */
10600c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         putXMMRegLane64( gregOfRM(modrm), 0,
10601c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                          loadLE(Ity_I64, mkexpr(addr)) );
10602c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         DIP("movsd %s,%s\n", dis_buf,
10603c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                              nameXMMReg(gregOfRM(modrm)));
10604c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+alen;
10605c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10606c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      goto decode_success;
10607c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10608c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj
10609c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10610c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      or lo half xmm). */
10611c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x11) {
10612c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      vassert(sz == 4);
10613c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      modrm = getIByte(delta+3);
10614c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      if (epartIsReg(modrm)) {
10615b7ba04ff6522c540cea057c4124e675b5f64ec46sewardj         putXMMRegLane64( eregOfRM(modrm), 0,
10616b7ba04ff6522c540cea057c4124e675b5f64ec46sewardj                          getXMMRegLane64( gregOfRM(modrm), 0 ));
10617b7ba04ff6522c540cea057c4124e675b5f64ec46sewardj         DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
10618b7ba04ff6522c540cea057c4124e675b5f64ec46sewardj                              nameXMMReg(eregOfRM(modrm)));
10619b7ba04ff6522c540cea057c4124e675b5f64ec46sewardj         delta += 3+1;
10620c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      } else {
10621c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10622c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         storeLE( mkexpr(addr),
10623519d66fc0e4f16b120079bc651862e49f154da62sewardj                  getXMMRegLane64(gregOfRM(modrm), 0) );
10624519d66fc0e4f16b120079bc651862e49f154da62sewardj         DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
10625c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj                              dis_buf);
10626c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj         delta += 3+alen;
10627c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj      }
10628b7ba04ff6522c540cea057c4124e675b5f64ec46sewardj      goto decode_success;
10629c2feffc51c90d2c3e324f30830bd48882e1288d3sewardj   }
10630fd22645d1e2445a568dda9ae665bd3a1315dea58sewardj
10631008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10632008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
10633008754b1685e50d117f9c982ddeeafbaca151bfesewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
10634008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10635008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10636008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10637008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
10638008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
10639008754b1685e50d117f9c982ddeeafbaca151bfesewardj      vassert(sz == 4);
10640008754b1685e50d117f9c982ddeeafbaca151bfesewardj      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
10641008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10642008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10643008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10644008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 56 = ORPD -- G = G and E */
10645008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
10646f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_OrV128 );
10647008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10648008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10649008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10650008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10651008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
10652008754b1685e50d117f9c982ddeeafbaca151bfesewardj      Int    select;
10653008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp sV = newTemp(Ity_V128);
10654008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp dV = newTemp(Ity_V128);
10655008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp s1 = newTemp(Ity_I64);
10656008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp s0 = newTemp(Ity_I64);
10657008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp d1 = newTemp(Ity_I64);
10658008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp d0 = newTemp(Ity_I64);
10659008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10660008754b1685e50d117f9c982ddeeafbaca151bfesewardj      modrm = insn[2];
10661008754b1685e50d117f9c982ddeeafbaca151bfesewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
10662008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10663008754b1685e50d117f9c982ddeeafbaca151bfesewardj      if (epartIsReg(modrm)) {
10664008754b1685e50d117f9c982ddeeafbaca151bfesewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
10665008754b1685e50d117f9c982ddeeafbaca151bfesewardj         select = (Int)insn[3];
10666008754b1685e50d117f9c982ddeeafbaca151bfesewardj         delta += 2+2;
10667008754b1685e50d117f9c982ddeeafbaca151bfesewardj         DIP("shufpd $%d,%s,%s\n", select,
10668008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                   nameXMMReg(eregOfRM(modrm)),
10669008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                   nameXMMReg(gregOfRM(modrm)));
10670008754b1685e50d117f9c982ddeeafbaca151bfesewardj      } else {
10671008754b1685e50d117f9c982ddeeafbaca151bfesewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10672008754b1685e50d117f9c982ddeeafbaca151bfesewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10673008754b1685e50d117f9c982ddeeafbaca151bfesewardj         select = (Int)insn[2+alen];
10674008754b1685e50d117f9c982ddeeafbaca151bfesewardj         delta += 3+alen;
10675008754b1685e50d117f9c982ddeeafbaca151bfesewardj         DIP("shufpd $%d,%s,%s\n", select,
10676008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                   dis_buf,
10677008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                   nameXMMReg(gregOfRM(modrm)));
10678008754b1685e50d117f9c982ddeeafbaca151bfesewardj      }
10679008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10680f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10681f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( d0, unop(Iop_V128to64,   mkexpr(dV)) );
10682f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10683f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( s0, unop(Iop_V128to64,   mkexpr(sV)) );
10684008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10685008754b1685e50d117f9c982ddeeafbaca151bfesewardj#     define SELD(n) mkexpr((n)==0 ? d0 : d1)
10686008754b1685e50d117f9c982ddeeafbaca151bfesewardj#     define SELS(n) mkexpr((n)==0 ? s0 : s1)
10687008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10688008754b1685e50d117f9c982ddeeafbaca151bfesewardj      putXMMReg(
10689008754b1685e50d117f9c982ddeeafbaca151bfesewardj         gregOfRM(modrm),
10690f0c1c58d6e47608ce166058997f795f1d7d45127sewardj         binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
10691008754b1685e50d117f9c982ddeeafbaca151bfesewardj      );
10692008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10693008754b1685e50d117f9c982ddeeafbaca151bfesewardj#     undef SELD
10694008754b1685e50d117f9c982ddeeafbaca151bfesewardj#     undef SELS
10695008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10696008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10697008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10698008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10699008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10700008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
10701008754b1685e50d117f9c982ddeeafbaca151bfesewardj      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
10702008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                        "sqrtpd", Iop_Sqrt64Fx2 );
10703008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10704008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10705008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10706008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10707008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
10708008754b1685e50d117f9c982ddeeafbaca151bfesewardj      vassert(sz == 4);
10709008754b1685e50d117f9c982ddeeafbaca151bfesewardj      delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3,
10710008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                         "sqrtsd", Iop_Sqrt64F0x2 );
10711008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10712008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10713008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10714008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10715008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
10716008754b1685e50d117f9c982ddeeafbaca151bfesewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
10717008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10718008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10719008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10720008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10721008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
10722008754b1685e50d117f9c982ddeeafbaca151bfesewardj      vassert(sz == 4);
10723008754b1685e50d117f9c982ddeeafbaca151bfesewardj      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
10724008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10725008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10726008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10727008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10728008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10729008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* These just appear to be special cases of SHUFPS */
10730008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10731008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp s1 = newTemp(Ity_I64);
10732008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp s0 = newTemp(Ity_I64);
10733008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp d1 = newTemp(Ity_I64);
10734008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp d0 = newTemp(Ity_I64);
10735008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp sV = newTemp(Ity_V128);
10736008754b1685e50d117f9c982ddeeafbaca151bfesewardj      IRTemp dV = newTemp(Ity_V128);
107372d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      Bool   hi = toBool(insn[1] == 0x15);
10738008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10739008754b1685e50d117f9c982ddeeafbaca151bfesewardj      modrm = insn[2];
10740008754b1685e50d117f9c982ddeeafbaca151bfesewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
10741008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10742008754b1685e50d117f9c982ddeeafbaca151bfesewardj      if (epartIsReg(modrm)) {
10743008754b1685e50d117f9c982ddeeafbaca151bfesewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
10744008754b1685e50d117f9c982ddeeafbaca151bfesewardj         delta += 2+1;
10745008754b1685e50d117f9c982ddeeafbaca151bfesewardj         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10746008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                  nameXMMReg(eregOfRM(modrm)),
10747008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                  nameXMMReg(gregOfRM(modrm)));
10748008754b1685e50d117f9c982ddeeafbaca151bfesewardj      } else {
10749008754b1685e50d117f9c982ddeeafbaca151bfesewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10750008754b1685e50d117f9c982ddeeafbaca151bfesewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10751008754b1685e50d117f9c982ddeeafbaca151bfesewardj         delta += 2+alen;
10752008754b1685e50d117f9c982ddeeafbaca151bfesewardj         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10753008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                  dis_buf,
10754008754b1685e50d117f9c982ddeeafbaca151bfesewardj                                  nameXMMReg(gregOfRM(modrm)));
10755008754b1685e50d117f9c982ddeeafbaca151bfesewardj      }
10756008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10757f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10758f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( d0, unop(Iop_V128to64,   mkexpr(dV)) );
10759f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10760f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( s0, unop(Iop_V128to64,   mkexpr(sV)) );
10761008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10762008754b1685e50d117f9c982ddeeafbaca151bfesewardj      if (hi) {
10763008754b1685e50d117f9c982ddeeafbaca151bfesewardj         putXMMReg( gregOfRM(modrm),
10764f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                    binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
10765008754b1685e50d117f9c982ddeeafbaca151bfesewardj      } else {
10766008754b1685e50d117f9c982ddeeafbaca151bfesewardj         putXMMReg( gregOfRM(modrm),
10767f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                    binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
10768008754b1685e50d117f9c982ddeeafbaca151bfesewardj      }
10769008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10770008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10771008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10772008754b1685e50d117f9c982ddeeafbaca151bfesewardj
10773008754b1685e50d117f9c982ddeeafbaca151bfesewardj   /* 66 0F 57 = XORPD -- G = G and E */
10774008754b1685e50d117f9c982ddeeafbaca151bfesewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
10775f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_XorV128 );
10776008754b1685e50d117f9c982ddeeafbaca151bfesewardj      goto decode_success;
10777008754b1685e50d117f9c982ddeeafbaca151bfesewardj   }
10778636ad762e49597ef608323f27c7b8eb66962cd90sewardj
10779164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F 6B = PACKSSDW */
10780164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
10781164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10782c9bff7dbb37ba2ee5898ef49aefaa92095ab446bsewardj                                 "packssdw",
107835f438dd73072211989c6d496845bdc9b777ecbecsewardj                                 Iop_QNarrowBin32Sto16Sx8, True );
10784164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10785164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10786164f9275c465cd09ecd09276b8542282f5def250sewardj
10787164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F 63 = PACKSSWB */
10788164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
10789164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10790c9bff7dbb37ba2ee5898ef49aefaa92095ab446bsewardj                                 "packsswb",
107915f438dd73072211989c6d496845bdc9b777ecbecsewardj                                 Iop_QNarrowBin16Sto8Sx16, True );
10792164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10793164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10794164f9275c465cd09ecd09276b8542282f5def250sewardj
10795164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F 67 = PACKUSWB */
10796164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
10797164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10798c9bff7dbb37ba2ee5898ef49aefaa92095ab446bsewardj                                 "packuswb",
107995f438dd73072211989c6d496845bdc9b777ecbecsewardj                                 Iop_QNarrowBin16Sto8Ux16, True );
10800164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10801164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10802164f9275c465cd09ecd09276b8542282f5def250sewardj
10803164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F FC = PADDB */
10804164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
10805164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10806164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddb", Iop_Add8x16, False );
10807164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10808164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10809164f9275c465cd09ecd09276b8542282f5def250sewardj
10810164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F FE = PADDD */
10811164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
10812164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10813164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddd", Iop_Add32x4, False );
10814164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10815164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10816164f9275c465cd09ecd09276b8542282f5def250sewardj
10817164f9275c465cd09ecd09276b8542282f5def250sewardj   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10818164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 0F D4 = PADDQ -- add 64x1 */
10819164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
10820164f9275c465cd09ecd09276b8542282f5def250sewardj      do_MMX_preamble();
10821164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_MMXop_regmem_to_reg (
10822164f9275c465cd09ecd09276b8542282f5def250sewardj                sorb, delta+2, insn[1], "paddq", False );
10823164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10824164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10825164f9275c465cd09ecd09276b8542282f5def250sewardj
10826164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F D4 = PADDQ */
10827164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
10828164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10829164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddq", Iop_Add64x2, False );
10830164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10831164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10832164f9275c465cd09ecd09276b8542282f5def250sewardj
10833164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F FD = PADDW */
10834164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
10835164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10836164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddw", Iop_Add16x8, False );
10837164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10838164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10839164f9275c465cd09ecd09276b8542282f5def250sewardj
10840164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F EC = PADDSB */
10841164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
10842164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10843164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddsb", Iop_QAdd8Sx16, False );
10844164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10845164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10846164f9275c465cd09ecd09276b8542282f5def250sewardj
10847164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F ED = PADDSW */
10848164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
10849164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10850164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddsw", Iop_QAdd16Sx8, False );
10851164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10852164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10853164f9275c465cd09ecd09276b8542282f5def250sewardj
10854164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F DC = PADDUSB */
10855164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
10856164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10857164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddusb", Iop_QAdd8Ux16, False );
10858164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10859164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10860164f9275c465cd09ecd09276b8542282f5def250sewardj
10861164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F DD = PADDUSW */
10862164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
10863164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10864164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "paddusw", Iop_QAdd16Ux8, False );
10865164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10866164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10867164f9275c465cd09ecd09276b8542282f5def250sewardj
10868164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F DB = PAND */
10869164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
10870f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_AndV128 );
10871164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10872164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10873164f9275c465cd09ecd09276b8542282f5def250sewardj
10874164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F DF = PANDN */
10875164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
10876f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_AndV128 );
10877164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10878164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10879164f9275c465cd09ecd09276b8542282f5def250sewardj
10880164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F E0 = PAVGB */
10881164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
10882164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10883164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "pavgb", Iop_Avg8Ux16, False );
10884164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10885164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10886164f9275c465cd09ecd09276b8542282f5def250sewardj
10887164f9275c465cd09ecd09276b8542282f5def250sewardj   /* 66 0F E3 = PAVGW */
10888164f9275c465cd09ecd09276b8542282f5def250sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
10889164f9275c465cd09ecd09276b8542282f5def250sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10890164f9275c465cd09ecd09276b8542282f5def250sewardj                                 "pavgw", Iop_Avg16Ux8, False );
10891164f9275c465cd09ecd09276b8542282f5def250sewardj      goto decode_success;
10892164f9275c465cd09ecd09276b8542282f5def250sewardj   }
10893164f9275c465cd09ecd09276b8542282f5def250sewardj
10894e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F 74 = PCMPEQB */
10895e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
10896e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10897e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pcmpeqb", Iop_CmpEQ8x16, False );
10898e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
10899e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10900e5854d6d470f21677ec84f71d09129434b044246sewardj
10901e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F 76 = PCMPEQD */
10902e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
10903e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10904e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pcmpeqd", Iop_CmpEQ32x4, False );
10905e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
10906e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10907e5854d6d470f21677ec84f71d09129434b044246sewardj
10908e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F 75 = PCMPEQW */
10909e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
10910e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10911e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pcmpeqw", Iop_CmpEQ16x8, False );
10912e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
10913e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10914e5854d6d470f21677ec84f71d09129434b044246sewardj
10915e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F 64 = PCMPGTB */
10916e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
10917e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10918e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pcmpgtb", Iop_CmpGT8Sx16, False );
10919e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
10920e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10921e5854d6d470f21677ec84f71d09129434b044246sewardj
10922e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F 66 = PCMPGTD */
10923e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
10924e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10925e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pcmpgtd", Iop_CmpGT32Sx4, False );
10926e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
10927e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10928e5854d6d470f21677ec84f71d09129434b044246sewardj
10929e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F 65 = PCMPGTW */
10930e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
10931e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
10932e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pcmpgtw", Iop_CmpGT16Sx8, False );
10933e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
10934e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10935e5854d6d470f21677ec84f71d09129434b044246sewardj
10936e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10937e5854d6d470f21677ec84f71d09129434b044246sewardj      zero-extend of it in ireg(G). */
10938e5854d6d470f21677ec84f71d09129434b044246sewardj   if (insn[0] == 0x0F && insn[1] == 0xC5) {
10939e5854d6d470f21677ec84f71d09129434b044246sewardj      modrm = insn[2];
10940e5854d6d470f21677ec84f71d09129434b044246sewardj      if (sz == 2 && epartIsReg(modrm)) {
10941e5854d6d470f21677ec84f71d09129434b044246sewardj         t5 = newTemp(Ity_V128);
10942e5854d6d470f21677ec84f71d09129434b044246sewardj         t4 = newTemp(Ity_I16);
10943e5854d6d470f21677ec84f71d09129434b044246sewardj         assign(t5, getXMMReg(eregOfRM(modrm)));
10944e5854d6d470f21677ec84f71d09129434b044246sewardj         breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10945e5854d6d470f21677ec84f71d09129434b044246sewardj         switch (insn[3] & 7) {
10946e5854d6d470f21677ec84f71d09129434b044246sewardj            case 0:  assign(t4, unop(Iop_32to16,   mkexpr(t0))); break;
10947e5854d6d470f21677ec84f71d09129434b044246sewardj            case 1:  assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
10948e5854d6d470f21677ec84f71d09129434b044246sewardj            case 2:  assign(t4, unop(Iop_32to16,   mkexpr(t1))); break;
10949e5854d6d470f21677ec84f71d09129434b044246sewardj            case 3:  assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
10950e5854d6d470f21677ec84f71d09129434b044246sewardj            case 4:  assign(t4, unop(Iop_32to16,   mkexpr(t2))); break;
10951e5854d6d470f21677ec84f71d09129434b044246sewardj            case 5:  assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
10952e5854d6d470f21677ec84f71d09129434b044246sewardj            case 6:  assign(t4, unop(Iop_32to16,   mkexpr(t3))); break;
10953e5854d6d470f21677ec84f71d09129434b044246sewardj            case 7:  assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
10954ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj            default: vassert(0); /*NOTREACHED*/
10955e5854d6d470f21677ec84f71d09129434b044246sewardj         }
10956e5854d6d470f21677ec84f71d09129434b044246sewardj         putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
10957e5854d6d470f21677ec84f71d09129434b044246sewardj         DIP("pextrw $%d,%s,%s\n",
10958e5854d6d470f21677ec84f71d09129434b044246sewardj             (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
10959e5854d6d470f21677ec84f71d09129434b044246sewardj                           nameIReg(4,gregOfRM(modrm)));
10960e5854d6d470f21677ec84f71d09129434b044246sewardj         delta += 4;
10961e5854d6d470f21677ec84f71d09129434b044246sewardj         goto decode_success;
10962e5854d6d470f21677ec84f71d09129434b044246sewardj      }
10963e5854d6d470f21677ec84f71d09129434b044246sewardj      /* else fall through */
10964e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10965e5854d6d470f21677ec84f71d09129434b044246sewardj
10966e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
10967e5854d6d470f21677ec84f71d09129434b044246sewardj      put it into the specified lane of xmm(G). */
10968e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
10969e5854d6d470f21677ec84f71d09129434b044246sewardj      Int lane;
10970e5854d6d470f21677ec84f71d09129434b044246sewardj      t4 = newTemp(Ity_I16);
10971e5854d6d470f21677ec84f71d09129434b044246sewardj      modrm = insn[2];
10972e5854d6d470f21677ec84f71d09129434b044246sewardj
10973e5854d6d470f21677ec84f71d09129434b044246sewardj      if (epartIsReg(modrm)) {
10974e5854d6d470f21677ec84f71d09129434b044246sewardj         assign(t4, getIReg(2, eregOfRM(modrm)));
10975aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj         delta += 3+1;
10976aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj         lane = insn[3+1-1];
10977e5854d6d470f21677ec84f71d09129434b044246sewardj         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10978e5854d6d470f21677ec84f71d09129434b044246sewardj                                   nameIReg(2,eregOfRM(modrm)),
10979e5854d6d470f21677ec84f71d09129434b044246sewardj                                   nameXMMReg(gregOfRM(modrm)));
10980e5854d6d470f21677ec84f71d09129434b044246sewardj      } else {
10981aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10982aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj         delta += 3+alen;
10983aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj         lane = insn[3+alen-1];
10984aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj         assign(t4, loadLE(Ity_I16, mkexpr(addr)));
10985aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10986aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj                                   dis_buf,
10987aac7e0892368414ec669c0e1fcd3d39a7282c8d9sewardj                                   nameXMMReg(gregOfRM(modrm)));
10988e5854d6d470f21677ec84f71d09129434b044246sewardj      }
10989e5854d6d470f21677ec84f71d09129434b044246sewardj
10990e5854d6d470f21677ec84f71d09129434b044246sewardj      putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
10991e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
10992e5854d6d470f21677ec84f71d09129434b044246sewardj   }
10993e5854d6d470f21677ec84f71d09129434b044246sewardj
10994b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj   /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
10995b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      E(xmm or mem) to G(xmm) */
10996b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF5) {
10997b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp s1V  = newTemp(Ity_V128);
10998b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp s2V  = newTemp(Ity_V128);
10999b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp dV   = newTemp(Ity_V128);
11000b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp s1Hi = newTemp(Ity_I64);
11001b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp s1Lo = newTemp(Ity_I64);
11002b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp s2Hi = newTemp(Ity_I64);
11003b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp s2Lo = newTemp(Ity_I64);
11004b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp dHi  = newTemp(Ity_I64);
11005b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      IRTemp dLo  = newTemp(Ity_I64);
11006b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      modrm = insn[2];
11007b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      if (epartIsReg(modrm)) {
11008b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         assign( s1V, getXMMReg(eregOfRM(modrm)) );
11009b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         delta += 2+1;
11010b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11011b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                                nameXMMReg(gregOfRM(modrm)));
11012b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      } else {
11013b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11014b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11015b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         delta += 2+alen;
11016b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj         DIP("pmaddwd %s,%s\n", dis_buf,
11017b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                                nameXMMReg(gregOfRM(modrm)));
11018b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      }
11019b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( s2V, getXMMReg(gregOfRM(modrm)) );
11020b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11021b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( s1Lo, unop(Iop_V128to64,   mkexpr(s1V)) );
11022b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11023b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( s2Lo, unop(Iop_V128to64,   mkexpr(s2V)) );
11024b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( dHi, mkIRExprCCall(
11025b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      Ity_I64, 0/*regparms*/,
11026b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      "x86g_calculate_mmx_pmaddwd",
11027b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      &x86g_calculate_mmx_pmaddwd,
11028b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11029b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                   ));
11030b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( dLo, mkIRExprCCall(
11031b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      Ity_I64, 0/*regparms*/,
11032b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      "x86g_calculate_mmx_pmaddwd",
11033b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      &x86g_calculate_mmx_pmaddwd,
11034b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                      mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11035b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj                   ));
11036b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11037b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11038b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj      goto decode_success;
11039b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj   }
11040b8a3dea71c25ee2eee75e7f7de68435e4ead4286sewardj
11041e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F EE = PMAXSW -- 16x8 signed max */
11042e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
11043e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11044e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pmaxsw", Iop_Max16Sx8, False );
11045e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11046e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11047e5854d6d470f21677ec84f71d09129434b044246sewardj
11048e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
11049e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
11050e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11051e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pmaxub", Iop_Max8Ux16, False );
11052e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11053e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11054e5854d6d470f21677ec84f71d09129434b044246sewardj
11055e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F EA = PMINSW -- 16x8 signed min */
11056e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
11057e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11058e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pminsw", Iop_Min16Sx8, False );
11059e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11060e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11061e5854d6d470f21677ec84f71d09129434b044246sewardj
11062e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F DA = PMINUB -- 8x16 unsigned min */
11063e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
11064e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11065e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pminub", Iop_Min8Ux16, False );
11066e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11067e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11068e5854d6d470f21677ec84f71d09129434b044246sewardj
11069e13074c2c1321d069fb95806bdce64f9a3512341sewardj   /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes
11070e13074c2c1321d069fb95806bdce64f9a3512341sewardj      in xmm(E), turn them into a byte, and put zero-extend of it in
11071e13074c2c1321d069fb95806bdce64f9a3512341sewardj      ireg(G). */
11072e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
11073e5854d6d470f21677ec84f71d09129434b044246sewardj      modrm = insn[2];
11074e5854d6d470f21677ec84f71d09129434b044246sewardj      if (epartIsReg(modrm)) {
11075e5854d6d470f21677ec84f71d09129434b044246sewardj         t0 = newTemp(Ity_I64);
11076e5854d6d470f21677ec84f71d09129434b044246sewardj         t1 = newTemp(Ity_I64);
11077e5854d6d470f21677ec84f71d09129434b044246sewardj         assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
11078e5854d6d470f21677ec84f71d09129434b044246sewardj         assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
11079e5854d6d470f21677ec84f71d09129434b044246sewardj         t5 = newTemp(Ity_I32);
11080e13074c2c1321d069fb95806bdce64f9a3512341sewardj         assign(t5,
11081e13074c2c1321d069fb95806bdce64f9a3512341sewardj                unop(Iop_16Uto32,
11082e13074c2c1321d069fb95806bdce64f9a3512341sewardj                     binop(Iop_8HLto16,
11083e13074c2c1321d069fb95806bdce64f9a3512341sewardj                           unop(Iop_GetMSBs8x8, mkexpr(t1)),
11084e13074c2c1321d069fb95806bdce64f9a3512341sewardj                           unop(Iop_GetMSBs8x8, mkexpr(t0)))));
11085e5854d6d470f21677ec84f71d09129434b044246sewardj         putIReg(4, gregOfRM(modrm), mkexpr(t5));
11086e5854d6d470f21677ec84f71d09129434b044246sewardj         DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11087e5854d6d470f21677ec84f71d09129434b044246sewardj                                 nameIReg(4,gregOfRM(modrm)));
11088e5854d6d470f21677ec84f71d09129434b044246sewardj         delta += 3;
11089e5854d6d470f21677ec84f71d09129434b044246sewardj         goto decode_success;
11090e5854d6d470f21677ec84f71d09129434b044246sewardj      }
11091e5854d6d470f21677ec84f71d09129434b044246sewardj      /* else fall through */
11092e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11093e5854d6d470f21677ec84f71d09129434b044246sewardj
11094e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
11095e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
11096e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11097e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pmulhuw", Iop_MulHi16Ux8, False );
11098e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11099e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11100e5854d6d470f21677ec84f71d09129434b044246sewardj
11101e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
11102e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
11103e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11104e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pmulhw", Iop_MulHi16Sx8, False );
11105e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11106e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11107e5854d6d470f21677ec84f71d09129434b044246sewardj
11108e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F D5 = PMULHL -- 16x8 multiply */
11109e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
11110e5854d6d470f21677ec84f71d09129434b044246sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11111e5854d6d470f21677ec84f71d09129434b044246sewardj                                 "pmullw", Iop_Mul16x8, False );
11112e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11113e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11114e5854d6d470f21677ec84f71d09129434b044246sewardj
11115e5854d6d470f21677ec84f71d09129434b044246sewardj   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11116e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11117e5854d6d470f21677ec84f71d09129434b044246sewardj      0 to form 64-bit result */
11118e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
11119e5854d6d470f21677ec84f71d09129434b044246sewardj      IRTemp sV = newTemp(Ity_I64);
11120e5854d6d470f21677ec84f71d09129434b044246sewardj      IRTemp dV = newTemp(Ity_I64);
11121e5854d6d470f21677ec84f71d09129434b044246sewardj      t1 = newTemp(Ity_I32);
11122e5854d6d470f21677ec84f71d09129434b044246sewardj      t0 = newTemp(Ity_I32);
11123e5854d6d470f21677ec84f71d09129434b044246sewardj      modrm = insn[2];
11124e5854d6d470f21677ec84f71d09129434b044246sewardj
11125e5854d6d470f21677ec84f71d09129434b044246sewardj      do_MMX_preamble();
11126e5854d6d470f21677ec84f71d09129434b044246sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
11127e5854d6d470f21677ec84f71d09129434b044246sewardj
11128e5854d6d470f21677ec84f71d09129434b044246sewardj      if (epartIsReg(modrm)) {
11129e5854d6d470f21677ec84f71d09129434b044246sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
11130e5854d6d470f21677ec84f71d09129434b044246sewardj         delta += 2+1;
11131e5854d6d470f21677ec84f71d09129434b044246sewardj         DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
11132e5854d6d470f21677ec84f71d09129434b044246sewardj                                nameMMXReg(gregOfRM(modrm)));
11133e5854d6d470f21677ec84f71d09129434b044246sewardj      } else {
11134e5854d6d470f21677ec84f71d09129434b044246sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11135e5854d6d470f21677ec84f71d09129434b044246sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11136e5854d6d470f21677ec84f71d09129434b044246sewardj         delta += 2+alen;
11137e5854d6d470f21677ec84f71d09129434b044246sewardj         DIP("pmuludq %s,%s\n", dis_buf,
11138e5854d6d470f21677ec84f71d09129434b044246sewardj                                nameMMXReg(gregOfRM(modrm)));
11139e5854d6d470f21677ec84f71d09129434b044246sewardj      }
11140e5854d6d470f21677ec84f71d09129434b044246sewardj
11141e5854d6d470f21677ec84f71d09129434b044246sewardj      assign( t0, unop(Iop_64to32, mkexpr(dV)) );
11142e5854d6d470f21677ec84f71d09129434b044246sewardj      assign( t1, unop(Iop_64to32, mkexpr(sV)) );
11143e5854d6d470f21677ec84f71d09129434b044246sewardj      putMMXReg( gregOfRM(modrm),
11144e5854d6d470f21677ec84f71d09129434b044246sewardj                 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
11145e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11146e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11147e5854d6d470f21677ec84f71d09129434b044246sewardj
11148e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11149e5854d6d470f21677ec84f71d09129434b044246sewardj      0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
11150e5854d6d470f21677ec84f71d09129434b044246sewardj      half */
11151e5854d6d470f21677ec84f71d09129434b044246sewardj   /* This is a really poor translation -- could be improved if
11152e5854d6d470f21677ec84f71d09129434b044246sewardj      performance critical */
11153e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
11154e5854d6d470f21677ec84f71d09129434b044246sewardj      IRTemp sV, dV;
11155e5854d6d470f21677ec84f71d09129434b044246sewardj      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
11156e5854d6d470f21677ec84f71d09129434b044246sewardj      sV = newTemp(Ity_V128);
11157e5854d6d470f21677ec84f71d09129434b044246sewardj      dV = newTemp(Ity_V128);
11158e5854d6d470f21677ec84f71d09129434b044246sewardj      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
11159e5854d6d470f21677ec84f71d09129434b044246sewardj      t1 = newTemp(Ity_I64);
11160e5854d6d470f21677ec84f71d09129434b044246sewardj      t0 = newTemp(Ity_I64);
11161e5854d6d470f21677ec84f71d09129434b044246sewardj      modrm = insn[2];
11162e5854d6d470f21677ec84f71d09129434b044246sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
11163e5854d6d470f21677ec84f71d09129434b044246sewardj
11164e5854d6d470f21677ec84f71d09129434b044246sewardj      if (epartIsReg(modrm)) {
11165e5854d6d470f21677ec84f71d09129434b044246sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
11166e5854d6d470f21677ec84f71d09129434b044246sewardj         delta += 2+1;
11167e5854d6d470f21677ec84f71d09129434b044246sewardj         DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11168e5854d6d470f21677ec84f71d09129434b044246sewardj                                nameXMMReg(gregOfRM(modrm)));
11169e5854d6d470f21677ec84f71d09129434b044246sewardj      } else {
11170e5854d6d470f21677ec84f71d09129434b044246sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11171e5854d6d470f21677ec84f71d09129434b044246sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11172e5854d6d470f21677ec84f71d09129434b044246sewardj         delta += 2+alen;
11173e5854d6d470f21677ec84f71d09129434b044246sewardj         DIP("pmuludq %s,%s\n", dis_buf,
11174e5854d6d470f21677ec84f71d09129434b044246sewardj                                nameXMMReg(gregOfRM(modrm)));
11175e5854d6d470f21677ec84f71d09129434b044246sewardj      }
11176e5854d6d470f21677ec84f71d09129434b044246sewardj
11177e5854d6d470f21677ec84f71d09129434b044246sewardj      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
11178e5854d6d470f21677ec84f71d09129434b044246sewardj      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11179e5854d6d470f21677ec84f71d09129434b044246sewardj
11180e5854d6d470f21677ec84f71d09129434b044246sewardj      assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
11181e5854d6d470f21677ec84f71d09129434b044246sewardj      putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
11182e5854d6d470f21677ec84f71d09129434b044246sewardj      assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
11183e5854d6d470f21677ec84f71d09129434b044246sewardj      putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
11184e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11185e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11186e5854d6d470f21677ec84f71d09129434b044246sewardj
11187e5854d6d470f21677ec84f71d09129434b044246sewardj   /* 66 0F EB = POR */
11188e5854d6d470f21677ec84f71d09129434b044246sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
11189f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_OrV128 );
11190e5854d6d470f21677ec84f71d09129434b044246sewardj      goto decode_success;
11191e5854d6d470f21677ec84f71d09129434b044246sewardj   }
11192e5854d6d470f21677ec84f71d09129434b044246sewardj
111937b5b9983870e937182d0a3a411047397257310b3sewardj   /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
111947b5b9983870e937182d0a3a411047397257310b3sewardj      from E(xmm or mem) to G(xmm) */
111957b5b9983870e937182d0a3a411047397257310b3sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF6) {
111967b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp s1V  = newTemp(Ity_V128);
111977b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp s2V  = newTemp(Ity_V128);
111987b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp dV   = newTemp(Ity_V128);
111997b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp s1Hi = newTemp(Ity_I64);
112007b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp s1Lo = newTemp(Ity_I64);
112017b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp s2Hi = newTemp(Ity_I64);
112027b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp s2Lo = newTemp(Ity_I64);
112037b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp dHi  = newTemp(Ity_I64);
112047b5b9983870e937182d0a3a411047397257310b3sewardj      IRTemp dLo  = newTemp(Ity_I64);
112057b5b9983870e937182d0a3a411047397257310b3sewardj      modrm = insn[2];
112067b5b9983870e937182d0a3a411047397257310b3sewardj      if (epartIsReg(modrm)) {
112077b5b9983870e937182d0a3a411047397257310b3sewardj         assign( s1V, getXMMReg(eregOfRM(modrm)) );
112087b5b9983870e937182d0a3a411047397257310b3sewardj         delta += 2+1;
112097b5b9983870e937182d0a3a411047397257310b3sewardj         DIP("psadbw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
112107b5b9983870e937182d0a3a411047397257310b3sewardj                               nameXMMReg(gregOfRM(modrm)));
112117b5b9983870e937182d0a3a411047397257310b3sewardj      } else {
112127b5b9983870e937182d0a3a411047397257310b3sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
112137b5b9983870e937182d0a3a411047397257310b3sewardj         assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
112147b5b9983870e937182d0a3a411047397257310b3sewardj         delta += 2+alen;
112157b5b9983870e937182d0a3a411047397257310b3sewardj         DIP("psadbw %s,%s\n", dis_buf,
112167b5b9983870e937182d0a3a411047397257310b3sewardj                               nameXMMReg(gregOfRM(modrm)));
112177b5b9983870e937182d0a3a411047397257310b3sewardj      }
112187b5b9983870e937182d0a3a411047397257310b3sewardj      assign( s2V, getXMMReg(gregOfRM(modrm)) );
112197b5b9983870e937182d0a3a411047397257310b3sewardj      assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
112207b5b9983870e937182d0a3a411047397257310b3sewardj      assign( s1Lo, unop(Iop_V128to64,   mkexpr(s1V)) );
112217b5b9983870e937182d0a3a411047397257310b3sewardj      assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
112227b5b9983870e937182d0a3a411047397257310b3sewardj      assign( s2Lo, unop(Iop_V128to64,   mkexpr(s2V)) );
112237b5b9983870e937182d0a3a411047397257310b3sewardj      assign( dHi, mkIRExprCCall(
112247b5b9983870e937182d0a3a411047397257310b3sewardj                      Ity_I64, 0/*regparms*/,
112257b5b9983870e937182d0a3a411047397257310b3sewardj                      "x86g_calculate_mmx_psadbw",
112267b5b9983870e937182d0a3a411047397257310b3sewardj                      &x86g_calculate_mmx_psadbw,
112277b5b9983870e937182d0a3a411047397257310b3sewardj                      mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
112287b5b9983870e937182d0a3a411047397257310b3sewardj                   ));
112297b5b9983870e937182d0a3a411047397257310b3sewardj      assign( dLo, mkIRExprCCall(
112307b5b9983870e937182d0a3a411047397257310b3sewardj                      Ity_I64, 0/*regparms*/,
112317b5b9983870e937182d0a3a411047397257310b3sewardj                      "x86g_calculate_mmx_psadbw",
112327b5b9983870e937182d0a3a411047397257310b3sewardj                      &x86g_calculate_mmx_psadbw,
112337b5b9983870e937182d0a3a411047397257310b3sewardj                      mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
112347b5b9983870e937182d0a3a411047397257310b3sewardj                   ));
112357b5b9983870e937182d0a3a411047397257310b3sewardj      assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
112367b5b9983870e937182d0a3a411047397257310b3sewardj      putXMMReg(gregOfRM(modrm), mkexpr(dV));
112377b5b9983870e937182d0a3a411047397257310b3sewardj      goto decode_success;
112387b5b9983870e937182d0a3a411047397257310b3sewardj   }
112397b5b9983870e937182d0a3a411047397257310b3sewardj
11240b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
11241b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
11242b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      Int order;
11243b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      IRTemp sV, dV, s3, s2, s1, s0;
11244b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11245b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      sV = newTemp(Ity_V128);
11246b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      dV = newTemp(Ity_V128);
11247b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      modrm = insn[2];
11248b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      if (epartIsReg(modrm)) {
11249b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
11250b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         order = (Int)insn[3];
11251b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         delta += 2+2;
11252b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         DIP("pshufd $%d,%s,%s\n", order,
11253b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                   nameXMMReg(eregOfRM(modrm)),
11254b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                   nameXMMReg(gregOfRM(modrm)));
11255b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      } else {
11256b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11257b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11258b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj	 order = (Int)insn[2+alen];
11259b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         delta += 3+alen;
11260b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         DIP("pshufd $%d,%s,%s\n", order,
11261b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                   dis_buf,
11262b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                   nameXMMReg(gregOfRM(modrm)));
11263b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      }
11264b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11265b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11266b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj#     define SEL(n) \
11267b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11268b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      assign(dV,
11269b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj	     mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
11270b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                           SEL((order>>2)&3), SEL((order>>0)&3) )
11271b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      );
11272b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11273b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj#     undef SEL
11274b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11275b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11276b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11277b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
11278b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      mem) to G(xmm), and copy lower half */
11279b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
11280b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      Int order;
11281b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
11282b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11283b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      sV   = newTemp(Ity_V128);
11284b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      dV   = newTemp(Ity_V128);
11285b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      sVhi = newTemp(Ity_I64);
11286b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      dVhi = newTemp(Ity_I64);
11287b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      modrm = insn[3];
11288b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      if (epartIsReg(modrm)) {
11289b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
11290b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         order = (Int)insn[4];
11291b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         delta += 4+1;
11292b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         DIP("pshufhw $%d,%s,%s\n", order,
11293b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    nameXMMReg(eregOfRM(modrm)),
11294b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    nameXMMReg(gregOfRM(modrm)));
11295b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      } else {
11296b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11297b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11298b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj	 order = (Int)insn[3+alen];
11299b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         delta += 4+alen;
11300b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         DIP("pshufhw $%d,%s,%s\n", order,
11301b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    dis_buf,
11302b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    nameXMMReg(gregOfRM(modrm)));
11303b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      }
11304f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
11305b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
11306b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11307b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj#     define SEL(n) \
11308b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11309b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      assign(dVhi,
11310b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11311b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                          SEL((order>>2)&3), SEL((order>>0)&3) )
11312b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      );
11313f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign(dV, binop( Iop_64HLtoV128,
11314b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                        mkexpr(dVhi),
11315f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                        unop(Iop_V128to64, mkexpr(sV))) );
11316b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11317b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj#     undef SEL
11318b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11319b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11320b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11321b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
11322b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      mem) to G(xmm), and copy upper half */
11323b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
11324b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      Int order;
11325b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
11326b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      s3 = s2 = s1 = s0 = IRTemp_INVALID;
11327b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      sV   = newTemp(Ity_V128);
11328b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      dV   = newTemp(Ity_V128);
11329b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      sVlo = newTemp(Ity_I64);
11330b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      dVlo = newTemp(Ity_I64);
11331b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      modrm = insn[3];
11332b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      if (epartIsReg(modrm)) {
11333b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
11334b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         order = (Int)insn[4];
11335b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         delta += 4+1;
11336b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         DIP("pshuflw $%d,%s,%s\n", order,
11337b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    nameXMMReg(eregOfRM(modrm)),
11338b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    nameXMMReg(gregOfRM(modrm)));
11339b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      } else {
11340b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11341b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11342b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj	 order = (Int)insn[3+alen];
11343b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         delta += 4+alen;
11344b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj         DIP("pshuflw $%d,%s,%s\n", order,
11345b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    dis_buf,
11346b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                    nameXMMReg(gregOfRM(modrm)));
11347b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      }
11348f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
11349b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
11350b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11351b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj#     define SEL(n) \
11352b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11353b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      assign(dVlo,
11354b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11355b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                          SEL((order>>2)&3), SEL((order>>0)&3) )
11356b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      );
11357f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign(dV, binop( Iop_64HLtoV128,
11358f0c1c58d6e47608ce166058997f795f1d7d45127sewardj                        unop(Iop_V128HIto64, mkexpr(sV)),
11359b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                        mkexpr(dVlo) ) );
11360b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      putXMMReg(gregOfRM(modrm), mkexpr(dV));
11361b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj#     undef SEL
11362b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11363b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11364b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11365b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 72 /6 ib = PSLLD by immediate */
11366b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11367b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11368b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 6) {
1136938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
11370b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11371b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11372b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11373b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F F2 = PSLLD by E */
11374b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
11375b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
11376b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11377b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11378b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11379b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 73 /7 ib = PSLLDQ by immediate */
11380b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11381b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11382b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 7) {
113830c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
113840c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      Int    imm = (Int)insn[3];
113850c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      Int    reg = eregOfRM(insn[2]);
113860c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
113870c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      vassert(imm >= 0 && imm <= 255);
113880c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      delta += 4;
113890c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj
113900c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      sV    = newTemp(Ity_V128);
113910c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      dV    = newTemp(Ity_V128);
113920c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      hi64  = newTemp(Ity_I64);
113930c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      lo64  = newTemp(Ity_I64);
113940c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      hi64r = newTemp(Ity_I64);
113950c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      lo64r = newTemp(Ity_I64);
113960c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj
113970c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      if (imm >= 16) {
113980c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         putXMMReg(reg, mkV128(0x0000));
113990c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         goto decode_success;
114000c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      }
114010c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj
114020c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      assign( sV, getXMMReg(reg) );
11403f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11404f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
114050c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj
11406ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      if (imm == 0) {
11407ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj         assign( lo64r, mkexpr(lo64) );
11408ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj         assign( hi64r, mkexpr(hi64) );
11409ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      }
11410ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      else
114110c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      if (imm == 8) {
114120c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         assign( lo64r, mkU64(0) );
114130c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         assign( hi64r, mkexpr(lo64) );
114140c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      }
11415c02043c8887e97cf6e9ae02a02edd3a84d92fb58sewardj      else
114160c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      if (imm > 8) {
114170c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         assign( lo64r, mkU64(0) );
114180c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         assign( hi64r, binop( Iop_Shl64,
114190c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                               mkexpr(lo64),
114200c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                               mkU8( 8*(imm-8) ) ));
114210c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      } else {
114220c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         assign( lo64r, binop( Iop_Shl64,
114230c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                               mkexpr(lo64),
114240c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                               mkU8(8 * imm) ));
114250c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj         assign( hi64r,
114260c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                 binop( Iop_Or64,
114270c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                        binop(Iop_Shl64, mkexpr(hi64),
114280c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                                         mkU8(8 * imm)),
114290c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                        binop(Iop_Shr64, mkexpr(lo64),
114300c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                                         mkU8(8 * (8 - imm)) )
114310c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj                      )
114320c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj               );
114330c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      }
11434f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
114350c9907cfabd6c5c89cb0055f7cbdab3e433076f8sewardj      putXMMReg(reg, mkexpr(dV));
11436b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11437b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11438b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11439b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 73 /6 ib = PSLLQ by immediate */
11440b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11441b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11442b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 6) {
1144338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
11444b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11445b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11446b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11447b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F F3 = PSLLQ by E */
11448b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
11449b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
11450b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11451b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11452b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11453b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 71 /6 ib = PSLLW by immediate */
11454b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11455b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11456b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 6) {
1145738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
11458b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11459b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11460b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11461b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F F1 = PSLLW by E */
11462b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
11463b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
11464b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11465b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11466b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11467b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 72 /4 ib = PSRAD by immediate */
11468b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11469b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11470b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 4) {
1147138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
11472b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11473b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11474b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11475b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F E2 = PSRAD by E */
11476b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
11477b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
11478b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11479b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11480b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11481b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 71 /4 ib = PSRAW by immediate */
11482b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11483b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11484b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 4) {
1148538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
11486b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11487b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11488b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11489b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F E1 = PSRAW by E */
11490b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
11491b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
11492b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11493b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11494b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11495b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 72 /2 ib = PSRLD by immediate */
11496b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11497b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11498b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 2) {
1149938a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
11500b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11501b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11502b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11503b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F D2 = PSRLD by E */
11504b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
11505b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
11506b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11507b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11508b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
115099ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj   /* 66 0F 73 /3 ib = PSRLDQ by immediate */
115109ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
115119ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj       && epartIsReg(insn[2])
1151295535feeb27c5641608bc9eb83c047837281a7f4sewardj       && gregOfRM(insn[2]) == 3) {
1151395535feeb27c5641608bc9eb83c047837281a7f4sewardj      IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
115149ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      Int    imm = (Int)insn[3];
115159ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      Int    reg = eregOfRM(insn[2]);
1151695535feeb27c5641608bc9eb83c047837281a7f4sewardj      DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
1151795535feeb27c5641608bc9eb83c047837281a7f4sewardj      vassert(imm >= 0 && imm <= 255);
115189ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      delta += 4;
1151995535feeb27c5641608bc9eb83c047837281a7f4sewardj
1152095535feeb27c5641608bc9eb83c047837281a7f4sewardj      sV    = newTemp(Ity_V128);
1152195535feeb27c5641608bc9eb83c047837281a7f4sewardj      dV    = newTemp(Ity_V128);
1152295535feeb27c5641608bc9eb83c047837281a7f4sewardj      hi64  = newTemp(Ity_I64);
1152395535feeb27c5641608bc9eb83c047837281a7f4sewardj      lo64  = newTemp(Ity_I64);
1152495535feeb27c5641608bc9eb83c047837281a7f4sewardj      hi64r = newTemp(Ity_I64);
1152595535feeb27c5641608bc9eb83c047837281a7f4sewardj      lo64r = newTemp(Ity_I64);
1152695535feeb27c5641608bc9eb83c047837281a7f4sewardj
1152795535feeb27c5641608bc9eb83c047837281a7f4sewardj      if (imm >= 16) {
1152895535feeb27c5641608bc9eb83c047837281a7f4sewardj         putXMMReg(reg, mkV128(0x0000));
1152995535feeb27c5641608bc9eb83c047837281a7f4sewardj         goto decode_success;
1153095535feeb27c5641608bc9eb83c047837281a7f4sewardj      }
1153195535feeb27c5641608bc9eb83c047837281a7f4sewardj
115329ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      assign( sV, getXMMReg(reg) );
11533f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11534f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
1153595535feeb27c5641608bc9eb83c047837281a7f4sewardj
11536ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      if (imm == 0) {
11537ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj         assign( lo64r, mkexpr(lo64) );
11538ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj         assign( hi64r, mkexpr(hi64) );
11539ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      }
11540ba89f4cf4da29a034487e0f3c73e23bbadd99cb6sewardj      else
1154195535feeb27c5641608bc9eb83c047837281a7f4sewardj      if (imm == 8) {
1154295535feeb27c5641608bc9eb83c047837281a7f4sewardj         assign( hi64r, mkU64(0) );
1154395535feeb27c5641608bc9eb83c047837281a7f4sewardj         assign( lo64r, mkexpr(hi64) );
1154495535feeb27c5641608bc9eb83c047837281a7f4sewardj      }
1154595535feeb27c5641608bc9eb83c047837281a7f4sewardj      else
1154695535feeb27c5641608bc9eb83c047837281a7f4sewardj      if (imm > 8) {
1154795535feeb27c5641608bc9eb83c047837281a7f4sewardj         assign( hi64r, mkU64(0) );
1154895535feeb27c5641608bc9eb83c047837281a7f4sewardj         assign( lo64r, binop( Iop_Shr64,
1154995535feeb27c5641608bc9eb83c047837281a7f4sewardj                               mkexpr(hi64),
1155095535feeb27c5641608bc9eb83c047837281a7f4sewardj                               mkU8( 8*(imm-8) ) ));
1155195535feeb27c5641608bc9eb83c047837281a7f4sewardj      } else {
1155295535feeb27c5641608bc9eb83c047837281a7f4sewardj         assign( hi64r, binop( Iop_Shr64,
1155395535feeb27c5641608bc9eb83c047837281a7f4sewardj                               mkexpr(hi64),
1155495535feeb27c5641608bc9eb83c047837281a7f4sewardj                               mkU8(8 * imm) ));
1155595535feeb27c5641608bc9eb83c047837281a7f4sewardj         assign( lo64r,
1155695535feeb27c5641608bc9eb83c047837281a7f4sewardj                 binop( Iop_Or64,
1155795535feeb27c5641608bc9eb83c047837281a7f4sewardj                        binop(Iop_Shr64, mkexpr(lo64),
1155895535feeb27c5641608bc9eb83c047837281a7f4sewardj                                         mkU8(8 * imm)),
1155995535feeb27c5641608bc9eb83c047837281a7f4sewardj                        binop(Iop_Shl64, mkexpr(hi64),
1156095535feeb27c5641608bc9eb83c047837281a7f4sewardj                                         mkU8(8 * (8 - imm)) )
1156195535feeb27c5641608bc9eb83c047837281a7f4sewardj                      )
1156295535feeb27c5641608bc9eb83c047837281a7f4sewardj               );
1156395535feeb27c5641608bc9eb83c047837281a7f4sewardj      }
1156495535feeb27c5641608bc9eb83c047837281a7f4sewardj
11565f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
115669ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      putXMMReg(reg, mkexpr(dV));
115679ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj      goto decode_success;
115689ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj   }
115699ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj
11570b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 73 /2 ib = PSRLQ by immediate */
11571b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11572b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11573b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 2) {
1157438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
11575b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11576b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11577b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11578b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F D3 = PSRLQ by E */
11579b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
11580b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
11581b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11582b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11583b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11584b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F 71 /2 ib = PSRLW by immediate */
11585b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11586b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && epartIsReg(insn[2])
11587b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj       && gregOfRM(insn[2]) == 2) {
1158838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
11589b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11590b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11591b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11592b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F D1 = PSRLW by E */
11593b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
11594b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
11595b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11596b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11597b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11598b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F F8 = PSUBB */
11599b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
11600b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11601b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubb", Iop_Sub8x16, False );
11602b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11603b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11604b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11605b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F FA = PSUBD */
11606b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
11607b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11608b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubd", Iop_Sub32x4, False );
11609b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11610b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11611b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11612b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11613b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 0F FB = PSUBQ -- sub 64x1 */
11614b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
11615b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      do_MMX_preamble();
11616b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_MMXop_regmem_to_reg (
11617b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                sorb, delta+2, insn[1], "psubq", False );
11618b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11619b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11620b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11621b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F FB = PSUBQ */
11622b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
11623b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11624b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubq", Iop_Sub64x2, False );
11625b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11626b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11627b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11628b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F F9 = PSUBW */
11629b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
11630b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11631b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubw", Iop_Sub16x8, False );
11632b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11633b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11634b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11635b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F E8 = PSUBSB */
11636b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
11637b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11638b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubsb", Iop_QSub8Sx16, False );
11639b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11640b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11641b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11642b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F E9 = PSUBSW */
11643b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
11644b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11645b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubsw", Iop_QSub16Sx8, False );
11646b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11647b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11648b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11649b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F D8 = PSUBSB */
11650b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
11651b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11652b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubusb", Iop_QSub8Ux16, False );
11653b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11654b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11655b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
11656b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   /* 66 0F D9 = PSUBSW */
11657b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
11658b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
11659b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj                                 "psubusw", Iop_QSub16Ux8, False );
11660b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj      goto decode_success;
11661b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj   }
11662b9fa69b4047ef2a1fd822bab909437c920b9c297sewardj
116639e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 68 = PUNPCKHBW */
116649e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
116659e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
116669e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpckhbw",
116679e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveHI8x16, True );
116689e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
116699e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
116709e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
116719e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 6A = PUNPCKHDQ */
116729e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
116739e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
116749e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpckhdq",
116759e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveHI32x4, True );
116769e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
116779e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
116789e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
116799e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 6D = PUNPCKHQDQ */
116809e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
116819e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
116829e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpckhqdq",
116839e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveHI64x2, True );
116849e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
116859e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
116869e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
116879e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 69 = PUNPCKHWD */
116889e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
116899e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
116909e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpckhwd",
116919e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveHI16x8, True );
116929e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
116939e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
116949e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
116959e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 60 = PUNPCKLBW */
116969e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
116979e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
116989e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpcklbw",
116999e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveLO8x16, True );
117009e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117019e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117029e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
117039e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 62 = PUNPCKLDQ */
117049e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
117059e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
117069e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpckldq",
117079e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveLO32x4, True );
117089e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117099e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117109e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
117119e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 6C = PUNPCKLQDQ */
117129e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
117139e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
117149e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpcklqdq",
117159e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveLO64x2, True );
117169e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117179e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117189e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
117199e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F 61 = PUNPCKLWD */
117209e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
117219e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      delta = dis_SSEint_E_to_G( sorb, delta+2,
117229e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 "punpcklwd",
117239e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj                                 Iop_InterleaveLO16x8, True );
117249e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117259e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117269e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
117279e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   /* 66 0F EF = PXOR */
117289e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
11729f0c1c58d6e47608ce166058997f795f1d7d45127sewardj      delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_XorV128 );
117309e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj      goto decode_success;
117319e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj   }
117329e20359bb34d2354a0726dde2b307e5d752a8ae6sewardj
11733c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--    /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11734c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--    if (insn[0] == 0x0F && insn[1] == 0xAE
11735c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--        && (!epartIsReg(insn[2]))
11736c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--        && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11737c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       Bool store = gregOfRM(insn[2]) == 0;
11738c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       vg_assert(sz == 4);
11739c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       pair = disAMode ( cb, sorb, eip+2, dis_buf );
11740c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       t1   = LOW24(pair);
11741c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       eip += 2+HI8(pair);
11742c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11743c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--                   Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11744c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--                   Lit16, (UShort)insn[2],
11745c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--                   TempReg, t1 );
11746c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11747c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       goto decode_success;
11748c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--    }
11749c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
11750bfceb089644ce9eee882bae5cec5902be4831cacsewardj   /* 0F AE /7 = CLFLUSH -- flush cache line */
11751bfceb089644ce9eee882bae5cec5902be4831cacsewardj   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
11752bfceb089644ce9eee882bae5cec5902be4831cacsewardj       && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
11753bfceb089644ce9eee882bae5cec5902be4831cacsewardj
11754bfceb089644ce9eee882bae5cec5902be4831cacsewardj      /* This is something of a hack.  We need to know the size of the
11755bfceb089644ce9eee882bae5cec5902be4831cacsewardj         cache line containing addr.  Since we don't (easily), assume
11756bfceb089644ce9eee882bae5cec5902be4831cacsewardj         256 on the basis that no real cache would have a line that
11757bfceb089644ce9eee882bae5cec5902be4831cacsewardj         big.  It's safe to invalidate more stuff than we need, just
11758bfceb089644ce9eee882bae5cec5902be4831cacsewardj         inefficient. */
11759bfceb089644ce9eee882bae5cec5902be4831cacsewardj      UInt lineszB = 256;
11760bfceb089644ce9eee882bae5cec5902be4831cacsewardj
11761bfceb089644ce9eee882bae5cec5902be4831cacsewardj      addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11762bfceb089644ce9eee882bae5cec5902be4831cacsewardj      delta += 2+alen;
11763bfceb089644ce9eee882bae5cec5902be4831cacsewardj
11764bfceb089644ce9eee882bae5cec5902be4831cacsewardj      /* Round addr down to the start of the containing block. */
11765bfceb089644ce9eee882bae5cec5902be4831cacsewardj      stmt( IRStmt_Put(
1176605f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj               OFFB_CMSTART,
11767bfceb089644ce9eee882bae5cec5902be4831cacsewardj               binop( Iop_And32,
11768bfceb089644ce9eee882bae5cec5902be4831cacsewardj                      mkexpr(addr),
11769bfceb089644ce9eee882bae5cec5902be4831cacsewardj                      mkU32( ~(lineszB-1) ))) );
11770bfceb089644ce9eee882bae5cec5902be4831cacsewardj
1177105f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj      stmt( IRStmt_Put(OFFB_CMLEN, mkU32(lineszB) ) );
11772bfceb089644ce9eee882bae5cec5902be4831cacsewardj
1177305f5e0172384dd2983fb16fbb7deebd74d71cd35sewardj      jmp_lit(&dres, Ijk_InvalICache, (Addr32)(guest_EIP_bbstart+delta));
11774bfceb089644ce9eee882bae5cec5902be4831cacsewardj
11775bfceb089644ce9eee882bae5cec5902be4831cacsewardj      DIP("clflush %s\n", dis_buf);
11776bfceb089644ce9eee882bae5cec5902be4831cacsewardj      goto decode_success;
11777bfceb089644ce9eee882bae5cec5902be4831cacsewardj   }
11778c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
11779c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* ---------------------------------------------------- */
1178090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* --- end of the SSE2 decoder.                     --- */
1178190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* ---------------------------------------------------- */
1178290e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1178390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* ---------------------------------------------------- */
1178490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* --- start of the SSE3 decoder.                   --- */
1178590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* ---------------------------------------------------- */
1178690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1178790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* Skip parts of the decoder which don't apply given the stated
1178890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      guest subarchitecture. */
117899f07e86cdca623c4c894a6864af0f936c685ea8fflorian   if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE3))
117905117ce116f47141cb23d1b49cc826e19323add97sewardj      goto after_sse_decoders; /* no SSE3 capabilities */
1179190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
117928462d113e3efeacceb304222dada8d85f748295aflorian   insn = &guest_code[delta];
1179390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1179490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
1179590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      duplicating some lanes (2:2:0:0). */
1179690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
1179790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      duplicating some lanes (3:3:1:1). */
1179890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   if (sz == 4 && insn[0] == 0xF3 && insn[1] == 0x0F
1179990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj       && (insn[2] == 0x12 || insn[2] == 0x16)) {
1180090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp s3, s2, s1, s0;
1180190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp sV  = newTemp(Ity_V128);
1180290e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      Bool   isH = insn[2] == 0x16;
1180390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      s3 = s2 = s1 = s0 = IRTemp_INVALID;
1180490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1180590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      modrm = insn[3];
1180690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      if (epartIsReg(modrm)) {
1180790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         assign( sV, getXMMReg( eregOfRM(modrm)) );
1180890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
1180990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj                                  nameXMMReg(eregOfRM(modrm)),
1181090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj                                  nameXMMReg(gregOfRM(modrm)));
1181190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         delta += 3+1;
1181290e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      } else {
1181390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
1181445ca0b9d0db9eaebae60b1d3b297cc06e87cfc4csewardj         gen_SEGV_if_not_16_aligned( addr );
1181590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
1181690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
1181790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj	     dis_buf,
1181890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj             nameXMMReg(gregOfRM(modrm)));
1181990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         delta += 3+alen;
1182090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      }
1182190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1182290e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
1182390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      putXMMReg( gregOfRM(modrm),
1182490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj                 isH ? mk128from32s( s3, s3, s1, s1 )
1182590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj                     : mk128from32s( s2, s2, s0, s0 ) );
1182690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      goto decode_success;
1182790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   }
1182890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
11829dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
11830dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      duplicating some lanes (0:1:0:1). */
11831dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x12) {
11832dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp sV = newTemp(Ity_V128);
11833dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp d0 = newTemp(Ity_I64);
11834dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11835dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      modrm = insn[3];
11836dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      if (epartIsReg(modrm)) {
11837dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( sV, getXMMReg( eregOfRM(modrm)) );
11838dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("movddup %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11839dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                nameXMMReg(gregOfRM(modrm)));
11840dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 3+1;
11841dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
11842dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      } else {
11843dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11844dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
11845dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("movddup %s,%s\n", dis_buf,
11846dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                nameXMMReg(gregOfRM(modrm)));
11847dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 3+alen;
11848dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      }
11849dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11850dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      putXMMReg( gregOfRM(modrm), binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
11851dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      goto decode_success;
11852dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   }
11853dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
1185490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
1185590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD0) {
1185690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
1185790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp eV   = newTemp(Ity_V128);
1185890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp gV   = newTemp(Ity_V128);
1185990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp addV = newTemp(Ity_V128);
1186090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      IRTemp subV = newTemp(Ity_V128);
118619571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      IRTemp rm     = newTemp(Ity_I32);
1186290e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
1186390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1186490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      modrm = insn[3];
1186590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      if (epartIsReg(modrm)) {
1186690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         assign( eV, getXMMReg( eregOfRM(modrm)) );
1186790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         DIP("addsubps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
1186890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj                                 nameXMMReg(gregOfRM(modrm)));
1186990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         delta += 3+1;
1187090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      } else {
1187190e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
1187290e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
1187390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         DIP("addsubps %s,%s\n", dis_buf,
1187490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj                                 nameXMMReg(gregOfRM(modrm)));
1187590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj         delta += 3+alen;
1187690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      }
1187790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1187890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      assign( gV, getXMMReg(gregOfRM(modrm)) );
1187990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
118809571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
118819571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( addV, triop(Iop_Add32Fx4, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
118829571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( subV, triop(Iop_Sub32Fx4, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
1188390e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1188490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      breakup128to32s( addV, &a3, &a2, &a1, &a0 );
1188590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      breakup128to32s( subV, &s3, &s2, &s1, &s0 );
1188690e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
1188790e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      putXMMReg( gregOfRM(modrm), mk128from32s( a3, s2, a1, s0 ));
1188890e91ee4a7b941c39e6f6df94fedf02649b14695sewardj      goto decode_success;
1188990e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   }
1189090e91ee4a7b941c39e6f6df94fedf02649b14695sewardj
11891dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
11892dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD0) {
11893dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp eV   = newTemp(Ity_V128);
11894dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp gV   = newTemp(Ity_V128);
11895dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp addV = newTemp(Ity_V128);
11896dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp subV = newTemp(Ity_V128);
11897dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp a1     = newTemp(Ity_I64);
11898dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp s0     = newTemp(Ity_I64);
118999571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      IRTemp rm     = newTemp(Ity_I32);
11900dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11901dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      modrm = insn[2];
11902dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      if (epartIsReg(modrm)) {
11903dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( eV, getXMMReg( eregOfRM(modrm)) );
11904dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11905dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                 nameXMMReg(gregOfRM(modrm)));
11906dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 2+1;
11907dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      } else {
11908dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11909dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11910dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("addsubpd %s,%s\n", dis_buf,
11911dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                 nameXMMReg(gregOfRM(modrm)));
11912dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 2+alen;
11913dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      }
11914dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11915dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( gV, getXMMReg(gregOfRM(modrm)) );
11916dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
119179571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
119189571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( addV, triop(Iop_Add64Fx2, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
119199571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( subV, triop(Iop_Sub64Fx2, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
11920dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11921dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
11922dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( s0, unop(Iop_V128to64,   mkexpr(subV) ));
11923dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11924dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      putXMMReg( gregOfRM(modrm),
11925dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
11926dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      goto decode_success;
11927dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   }
11928dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11929dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
11930dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
11931dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F
11932dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj       && (insn[2] == 0x7C || insn[2] == 0x7D)) {
11933dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
11934dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp eV     = newTemp(Ity_V128);
11935dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp gV     = newTemp(Ity_V128);
11936dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp leftV  = newTemp(Ity_V128);
11937dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp rightV = newTemp(Ity_V128);
119389571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      IRTemp rm     = newTemp(Ity_I32);
11939dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      Bool   isAdd  = insn[2] == 0x7C;
1194055085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = isAdd ? "add" : "sub";
11941dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
11942dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11943dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      modrm = insn[3];
11944dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      if (epartIsReg(modrm)) {
11945dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( eV, getXMMReg( eregOfRM(modrm)) );
11946dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11947dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                   nameXMMReg(gregOfRM(modrm)));
11948dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 3+1;
11949dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      } else {
11950dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11951dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11952dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("h%sps %s,%s\n", str, dis_buf,
11953dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                   nameXMMReg(gregOfRM(modrm)));
11954dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 3+alen;
11955dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      }
11956dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11957dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( gV, getXMMReg(gregOfRM(modrm)) );
11958dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11959dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      breakup128to32s( eV, &e3, &e2, &e1, &e0 );
11960dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      breakup128to32s( gV, &g3, &g2, &g1, &g0 );
11961dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11962dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( leftV,  mk128from32s( e2, e0, g2, g0 ) );
11963dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
11964dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
119659571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
11966dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      putXMMReg( gregOfRM(modrm),
119679571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                 triop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
119689571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                       mkexpr(rm), mkexpr(leftV), mkexpr(rightV) ) );
11969dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      goto decode_success;
11970dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   }
11971dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11972dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
11973dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
11974dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
11975dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp e1     = newTemp(Ity_I64);
11976dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp e0     = newTemp(Ity_I64);
11977dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp g1     = newTemp(Ity_I64);
11978dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp g0     = newTemp(Ity_I64);
11979dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp eV     = newTemp(Ity_V128);
11980dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp gV     = newTemp(Ity_V128);
11981dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp leftV  = newTemp(Ity_V128);
11982dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      IRTemp rightV = newTemp(Ity_V128);
119839571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      IRTemp rm     = newTemp(Ity_I32);
11984dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      Bool   isAdd  = insn[1] == 0x7C;
1198555085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = isAdd ? "add" : "sub";
11986dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
11987dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      modrm = insn[2];
11988dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      if (epartIsReg(modrm)) {
11989dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( eV, getXMMReg( eregOfRM(modrm)) );
11990dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11991dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                                   nameXMMReg(gregOfRM(modrm)));
11992dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 2+1;
11993dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      } else {
11994dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11995dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11996dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("h%spd %s,%s\n", str, dis_buf,
11997dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                              nameXMMReg(gregOfRM(modrm)));
11998dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 2+alen;
11999dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      }
12000dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
12001dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( gV, getXMMReg(gregOfRM(modrm)) );
12002dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
12003dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
12004dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
12005dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
12006dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
12007dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
12008dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( leftV,  binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
12009dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
12010dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
120119571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj      assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
12012dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      putXMMReg( gregOfRM(modrm),
120139571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                 triop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
120149571dc05739e7980539cfd9dbc4e9ca19324e6d6sewardj                       mkexpr(rm), mkexpr(leftV), mkexpr(rightV) ) );
12015dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      goto decode_success;
12016dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   }
12017dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
12018dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
12019dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xF0) {
12020dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      modrm = getIByte(delta+3);
12021dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      if (epartIsReg(modrm)) {
12022dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         goto decode_failure;
12023dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      } else {
12024dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12025dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         putXMMReg( gregOfRM(modrm),
12026dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                    loadLE(Ity_V128, mkexpr(addr)) );
12027dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         DIP("lddqu %s,%s\n", dis_buf,
12028dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj                              nameXMMReg(gregOfRM(modrm)));
12029dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj         delta += 3+alen;
12030dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      }
12031dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj      goto decode_success;
12032dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj   }
12033dd5d20442435b61950ebcfe9d686ab6632cce69bsewardj
1203490e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* ---------------------------------------------------- */
1203590e91ee4a7b941c39e6f6df94fedf02649b14695sewardj   /* --- end of the SSE3 decoder.                     --- */
12036c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* ---------------------------------------------------- */
12037c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
12038150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* ---------------------------------------------------- */
12039150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* --- start of the SSSE3 decoder.                  --- */
12040150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* ---------------------------------------------------- */
12041150c9cddb753ad4dc38f43484144523174d38b02sewardj
12042150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
12043150c9cddb753ad4dc38f43484144523174d38b02sewardj      Unsigned Bytes (MMX) */
12044150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12045150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
12046150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV        = newTemp(Ity_I64);
12047150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV        = newTemp(Ity_I64);
12048150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sVoddsSX  = newTemp(Ity_I64);
12049150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sVevensSX = newTemp(Ity_I64);
12050150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dVoddsZX  = newTemp(Ity_I64);
12051150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dVevensZX = newTemp(Ity_I64);
12052150c9cddb753ad4dc38f43484144523174d38b02sewardj
12053150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12054150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12055150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
12056150c9cddb753ad4dc38f43484144523174d38b02sewardj
12057150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12058150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12059150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12060150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmaddubsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12061150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameMMXReg(gregOfRM(modrm)));
12062150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12063150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12064150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12065150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12066150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmaddubsw %s,%s\n", dis_buf,
12067150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameMMXReg(gregOfRM(modrm)));
12068150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12069150c9cddb753ad4dc38f43484144523174d38b02sewardj
12070150c9cddb753ad4dc38f43484144523174d38b02sewardj      /* compute dV unsigned x sV signed */
12071150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sVoddsSX,
12072150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_SarN16x4, mkexpr(sV), mkU8(8)) );
12073150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sVevensSX,
12074150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_SarN16x4,
12075150c9cddb753ad4dc38f43484144523174d38b02sewardj                    binop(Iop_ShlN16x4, mkexpr(sV), mkU8(8)),
12076150c9cddb753ad4dc38f43484144523174d38b02sewardj                    mkU8(8)) );
12077150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dVoddsZX,
12078150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_ShrN16x4, mkexpr(dV), mkU8(8)) );
12079150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dVevensZX,
12080150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_ShrN16x4,
12081150c9cddb753ad4dc38f43484144523174d38b02sewardj                    binop(Iop_ShlN16x4, mkexpr(dV), mkU8(8)),
12082150c9cddb753ad4dc38f43484144523174d38b02sewardj                    mkU8(8)) );
12083150c9cddb753ad4dc38f43484144523174d38b02sewardj
12084150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg(
12085150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12086150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_QAdd16Sx4,
12087150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_Mul16x4, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
12088150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_Mul16x4, mkexpr(sVevensSX), mkexpr(dVevensZX))
12089150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12090150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12091150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12092150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12093150c9cddb753ad4dc38f43484144523174d38b02sewardj
12094150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
12095150c9cddb753ad4dc38f43484144523174d38b02sewardj      Unsigned Bytes (XMM) */
12096150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12097150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
12098150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV        = newTemp(Ity_V128);
12099150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV        = newTemp(Ity_V128);
12100150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sVoddsSX  = newTemp(Ity_V128);
12101150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sVevensSX = newTemp(Ity_V128);
12102150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dVoddsZX  = newTemp(Ity_V128);
12103150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dVevensZX = newTemp(Ity_V128);
12104150c9cddb753ad4dc38f43484144523174d38b02sewardj
12105150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12106150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
12107150c9cddb753ad4dc38f43484144523174d38b02sewardj
12108150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12109150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
12110150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12111150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmaddubsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12112150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameXMMReg(gregOfRM(modrm)));
12113150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12114150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12115150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12116150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12117150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12118150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmaddubsw %s,%s\n", dis_buf,
12119150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameXMMReg(gregOfRM(modrm)));
12120150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12121150c9cddb753ad4dc38f43484144523174d38b02sewardj
12122150c9cddb753ad4dc38f43484144523174d38b02sewardj      /* compute dV unsigned x sV signed */
12123150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sVoddsSX,
12124150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_SarN16x8, mkexpr(sV), mkU8(8)) );
12125150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sVevensSX,
12126150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_SarN16x8,
12127150c9cddb753ad4dc38f43484144523174d38b02sewardj                    binop(Iop_ShlN16x8, mkexpr(sV), mkU8(8)),
12128150c9cddb753ad4dc38f43484144523174d38b02sewardj                    mkU8(8)) );
12129150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dVoddsZX,
12130150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_ShrN16x8, mkexpr(dV), mkU8(8)) );
12131150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dVevensZX,
12132150c9cddb753ad4dc38f43484144523174d38b02sewardj              binop(Iop_ShrN16x8,
12133150c9cddb753ad4dc38f43484144523174d38b02sewardj                    binop(Iop_ShlN16x8, mkexpr(dV), mkU8(8)),
12134150c9cddb753ad4dc38f43484144523174d38b02sewardj                    mkU8(8)) );
12135150c9cddb753ad4dc38f43484144523174d38b02sewardj
12136150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12137150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12138150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_QAdd16Sx8,
12139150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_Mul16x8, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
12140150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_Mul16x8, mkexpr(sVevensSX), mkexpr(dVevensZX))
12141150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12142150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12143150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12144150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12145150c9cddb753ad4dc38f43484144523174d38b02sewardj
12146150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* ***--- these are MMX class insns introduced in SSSE3 ---*** */
12147150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 03 = PHADDSW -- 16x4 signed qadd across from E (mem or
12148150c9cddb753ad4dc38f43484144523174d38b02sewardj      mmx) and G to G (mmx). */
12149150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 07 = PHSUBSW -- 16x4 signed qsub across from E (mem or
12150150c9cddb753ad4dc38f43484144523174d38b02sewardj      mmx) and G to G (mmx). */
12151150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 01 = PHADDW -- 16x4 add across from E (mem or mmx) and G
12152150c9cddb753ad4dc38f43484144523174d38b02sewardj      to G (mmx). */
12153150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 05 = PHSUBW -- 16x4 sub across from E (mem or mmx) and G
12154150c9cddb753ad4dc38f43484144523174d38b02sewardj      to G (mmx). */
12155150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 02 = PHADDD -- 32x2 add across from E (mem or mmx) and G
12156150c9cddb753ad4dc38f43484144523174d38b02sewardj      to G (mmx). */
12157150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 06 = PHSUBD -- 32x2 sub across from E (mem or mmx) and G
12158150c9cddb753ad4dc38f43484144523174d38b02sewardj      to G (mmx). */
12159150c9cddb753ad4dc38f43484144523174d38b02sewardj
12160150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12161150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38
12162150c9cddb753ad4dc38f43484144523174d38b02sewardj       && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
12163150c9cddb753ad4dc38f43484144523174d38b02sewardj           || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
1216455085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = "???";
12165150c9cddb753ad4dc38f43484144523174d38b02sewardj      IROp   opV64  = Iop_INVALID;
12166150c9cddb753ad4dc38f43484144523174d38b02sewardj      IROp   opCatO = Iop_CatOddLanes16x4;
12167150c9cddb753ad4dc38f43484144523174d38b02sewardj      IROp   opCatE = Iop_CatEvenLanes16x4;
12168150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV     = newTemp(Ity_I64);
12169150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV     = newTemp(Ity_I64);
12170150c9cddb753ad4dc38f43484144523174d38b02sewardj
12171150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12172150c9cddb753ad4dc38f43484144523174d38b02sewardj
12173150c9cddb753ad4dc38f43484144523174d38b02sewardj      switch (insn[2]) {
12174150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
12175150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
12176150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x01: opV64 = Iop_Add16x4;   str = "addw";  break;
12177150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x05: opV64 = Iop_Sub16x4;   str = "subw";  break;
12178150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x02: opV64 = Iop_Add32x2;   str = "addd";  break;
12179150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x06: opV64 = Iop_Sub32x2;   str = "subd";  break;
12180150c9cddb753ad4dc38f43484144523174d38b02sewardj         default: vassert(0);
12181150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12182150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (insn[2] == 0x02 || insn[2] == 0x06) {
12183150c9cddb753ad4dc38f43484144523174d38b02sewardj         opCatO = Iop_InterleaveHI32x2;
12184150c9cddb753ad4dc38f43484144523174d38b02sewardj         opCatE = Iop_InterleaveLO32x2;
12185150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12186150c9cddb753ad4dc38f43484144523174d38b02sewardj
12187150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12188150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
12189150c9cddb753ad4dc38f43484144523174d38b02sewardj
12190150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12191150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12192150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12193150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("ph%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12194150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameMMXReg(gregOfRM(modrm)));
12195150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12196150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12197150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12198150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12199150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("ph%s %s,%s\n", str, dis_buf,
12200150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameMMXReg(gregOfRM(modrm)));
12201150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12202150c9cddb753ad4dc38f43484144523174d38b02sewardj
12203150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg(
12204150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12205150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(opV64,
12206150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(opCatE,mkexpr(sV),mkexpr(dV)),
12207150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(opCatO,mkexpr(sV),mkexpr(dV))
12208150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12209150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12210150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12211150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12212150c9cddb753ad4dc38f43484144523174d38b02sewardj
12213150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 03 = PHADDSW -- 16x8 signed qadd across from E (mem or
12214150c9cddb753ad4dc38f43484144523174d38b02sewardj      xmm) and G to G (xmm). */
12215150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 07 = PHSUBSW -- 16x8 signed qsub across from E (mem or
12216150c9cddb753ad4dc38f43484144523174d38b02sewardj      xmm) and G to G (xmm). */
12217150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 01 = PHADDW -- 16x8 add across from E (mem or xmm) and
12218150c9cddb753ad4dc38f43484144523174d38b02sewardj      G to G (xmm). */
12219150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 05 = PHSUBW -- 16x8 sub across from E (mem or xmm) and
12220150c9cddb753ad4dc38f43484144523174d38b02sewardj      G to G (xmm). */
12221150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 02 = PHADDD -- 32x4 add across from E (mem or xmm) and
12222150c9cddb753ad4dc38f43484144523174d38b02sewardj      G to G (xmm). */
12223150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 06 = PHSUBD -- 32x4 sub across from E (mem or xmm) and
12224150c9cddb753ad4dc38f43484144523174d38b02sewardj      G to G (xmm). */
12225150c9cddb753ad4dc38f43484144523174d38b02sewardj
12226150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12227150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38
12228150c9cddb753ad4dc38f43484144523174d38b02sewardj       && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
12229150c9cddb753ad4dc38f43484144523174d38b02sewardj           || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
1223055085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = "???";
12231150c9cddb753ad4dc38f43484144523174d38b02sewardj      IROp   opV64  = Iop_INVALID;
12232150c9cddb753ad4dc38f43484144523174d38b02sewardj      IROp   opCatO = Iop_CatOddLanes16x4;
12233150c9cddb753ad4dc38f43484144523174d38b02sewardj      IROp   opCatE = Iop_CatEvenLanes16x4;
12234150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV     = newTemp(Ity_V128);
12235150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV     = newTemp(Ity_V128);
12236150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sHi    = newTemp(Ity_I64);
12237150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sLo    = newTemp(Ity_I64);
12238150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dHi    = newTemp(Ity_I64);
12239150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dLo    = newTemp(Ity_I64);
12240150c9cddb753ad4dc38f43484144523174d38b02sewardj
12241150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12242150c9cddb753ad4dc38f43484144523174d38b02sewardj
12243150c9cddb753ad4dc38f43484144523174d38b02sewardj      switch (insn[2]) {
12244150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
12245150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
12246150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x01: opV64 = Iop_Add16x4;   str = "addw";  break;
12247150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x05: opV64 = Iop_Sub16x4;   str = "subw";  break;
12248150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x02: opV64 = Iop_Add32x2;   str = "addd";  break;
12249150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x06: opV64 = Iop_Sub32x2;   str = "subd";  break;
12250150c9cddb753ad4dc38f43484144523174d38b02sewardj         default: vassert(0);
12251150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12252150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (insn[2] == 0x02 || insn[2] == 0x06) {
12253150c9cddb753ad4dc38f43484144523174d38b02sewardj         opCatO = Iop_InterleaveHI32x2;
12254150c9cddb753ad4dc38f43484144523174d38b02sewardj         opCatE = Iop_InterleaveLO32x2;
12255150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12256150c9cddb753ad4dc38f43484144523174d38b02sewardj
12257150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
12258150c9cddb753ad4dc38f43484144523174d38b02sewardj
12259150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12260150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg( eregOfRM(modrm)) );
12261150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("ph%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12262150c9cddb753ad4dc38f43484144523174d38b02sewardj                                  nameXMMReg(gregOfRM(modrm)));
12263150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12264150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12265150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12266150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12267150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12268150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("ph%s %s,%s\n", str, dis_buf,
12269150c9cddb753ad4dc38f43484144523174d38b02sewardj                             nameXMMReg(gregOfRM(modrm)));
12270150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12271150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12272150c9cddb753ad4dc38f43484144523174d38b02sewardj
12273150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12274150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12275150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12276150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12277150c9cddb753ad4dc38f43484144523174d38b02sewardj
12278150c9cddb753ad4dc38f43484144523174d38b02sewardj      /* This isn't a particularly efficient way to compute the
12279150c9cddb753ad4dc38f43484144523174d38b02sewardj         result, but at least it avoids a proliferation of IROps,
12280150c9cddb753ad4dc38f43484144523174d38b02sewardj         hence avoids complication all the backends. */
12281150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12282150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12283150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_64HLtoV128,
12284150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(opV64,
12285150c9cddb753ad4dc38f43484144523174d38b02sewardj                     binop(opCatE,mkexpr(sHi),mkexpr(sLo)),
12286150c9cddb753ad4dc38f43484144523174d38b02sewardj                     binop(opCatO,mkexpr(sHi),mkexpr(sLo))
12287150c9cddb753ad4dc38f43484144523174d38b02sewardj               ),
12288150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(opV64,
12289150c9cddb753ad4dc38f43484144523174d38b02sewardj                     binop(opCatE,mkexpr(dHi),mkexpr(dLo)),
12290150c9cddb753ad4dc38f43484144523174d38b02sewardj                     binop(opCatO,mkexpr(dHi),mkexpr(dLo))
12291150c9cddb753ad4dc38f43484144523174d38b02sewardj               )
12292150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12293150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12294150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12295150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12296150c9cddb753ad4dc38f43484144523174d38b02sewardj
12297150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and Scale
12298150c9cddb753ad4dc38f43484144523174d38b02sewardj      (MMX) */
12299150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12300150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12301150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV = newTemp(Ity_I64);
12302150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV = newTemp(Ity_I64);
12303150c9cddb753ad4dc38f43484144523174d38b02sewardj
12304150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12305150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12306150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
12307150c9cddb753ad4dc38f43484144523174d38b02sewardj
12308150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12309150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12310150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12311150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmulhrsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12312150c9cddb753ad4dc38f43484144523174d38b02sewardj                                 nameMMXReg(gregOfRM(modrm)));
12313150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12314150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12315150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12316150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12317150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmulhrsw %s,%s\n", dis_buf,
12318150c9cddb753ad4dc38f43484144523174d38b02sewardj                                 nameMMXReg(gregOfRM(modrm)));
12319150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12320150c9cddb753ad4dc38f43484144523174d38b02sewardj
12321150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg(
12322150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12323150c9cddb753ad4dc38f43484144523174d38b02sewardj         dis_PMULHRSW_helper( mkexpr(sV), mkexpr(dV) )
12324150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12325150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12326150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12327150c9cddb753ad4dc38f43484144523174d38b02sewardj
12328150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and
12329150c9cddb753ad4dc38f43484144523174d38b02sewardj      Scale (XMM) */
12330150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12331150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12332150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV  = newTemp(Ity_V128);
12333150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV  = newTemp(Ity_V128);
12334150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sHi = newTemp(Ity_I64);
12335150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sLo = newTemp(Ity_I64);
12336150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dHi = newTemp(Ity_I64);
12337150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dLo = newTemp(Ity_I64);
12338150c9cddb753ad4dc38f43484144523174d38b02sewardj
12339150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12340150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
12341150c9cddb753ad4dc38f43484144523174d38b02sewardj
12342150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12343150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
12344150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12345150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmulhrsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12346150c9cddb753ad4dc38f43484144523174d38b02sewardj                                 nameXMMReg(gregOfRM(modrm)));
12347150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12348150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12349150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12350150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12351150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12352150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pmulhrsw %s,%s\n", dis_buf,
12353150c9cddb753ad4dc38f43484144523174d38b02sewardj                                 nameXMMReg(gregOfRM(modrm)));
12354150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12355150c9cddb753ad4dc38f43484144523174d38b02sewardj
12356150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12357150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12358150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12359150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12360150c9cddb753ad4dc38f43484144523174d38b02sewardj
12361150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12362150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12363150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_64HLtoV128,
12364150c9cddb753ad4dc38f43484144523174d38b02sewardj               dis_PMULHRSW_helper( mkexpr(sHi), mkexpr(dHi) ),
12365150c9cddb753ad4dc38f43484144523174d38b02sewardj               dis_PMULHRSW_helper( mkexpr(sLo), mkexpr(dLo) )
12366150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12367150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12368150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12369150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12370150c9cddb753ad4dc38f43484144523174d38b02sewardj
12371150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 08 = PSIGNB -- Packed Sign 8x8  (MMX) */
12372150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 09 = PSIGNW -- Packed Sign 16x4 (MMX) */
12373150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 09 = PSIGND -- Packed Sign 32x2 (MMX) */
12374150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12375150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38
12376150c9cddb753ad4dc38f43484144523174d38b02sewardj       && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12377150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV      = newTemp(Ity_I64);
12378150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV      = newTemp(Ity_I64);
1237955085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = "???";
12380150c9cddb753ad4dc38f43484144523174d38b02sewardj      Int    laneszB = 0;
12381150c9cddb753ad4dc38f43484144523174d38b02sewardj
12382150c9cddb753ad4dc38f43484144523174d38b02sewardj      switch (insn[2]) {
12383150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x08: laneszB = 1; str = "b"; break;
12384150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x09: laneszB = 2; str = "w"; break;
12385150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x0A: laneszB = 4; str = "d"; break;
12386150c9cddb753ad4dc38f43484144523174d38b02sewardj         default: vassert(0);
12387150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12388150c9cddb753ad4dc38f43484144523174d38b02sewardj
12389150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12390150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12391150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
12392150c9cddb753ad4dc38f43484144523174d38b02sewardj
12393150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12394150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12395150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12396150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("psign%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12397150c9cddb753ad4dc38f43484144523174d38b02sewardj                                     nameMMXReg(gregOfRM(modrm)));
12398150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12399150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12400150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12401150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12402150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("psign%s %s,%s\n", str, dis_buf,
12403150c9cddb753ad4dc38f43484144523174d38b02sewardj                                     nameMMXReg(gregOfRM(modrm)));
12404150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12405150c9cddb753ad4dc38f43484144523174d38b02sewardj
12406150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg(
12407150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12408150c9cddb753ad4dc38f43484144523174d38b02sewardj         dis_PSIGN_helper( mkexpr(sV), mkexpr(dV), laneszB )
12409150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12410150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12411150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12412150c9cddb753ad4dc38f43484144523174d38b02sewardj
12413150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 08 = PSIGNB -- Packed Sign 8x16 (XMM) */
12414150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 09 = PSIGNW -- Packed Sign 16x8 (XMM) */
12415150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 09 = PSIGND -- Packed Sign 32x4 (XMM) */
12416150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12417150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38
12418150c9cddb753ad4dc38f43484144523174d38b02sewardj       && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12419150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV      = newTemp(Ity_V128);
12420150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV      = newTemp(Ity_V128);
12421150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sHi     = newTemp(Ity_I64);
12422150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sLo     = newTemp(Ity_I64);
12423150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dHi     = newTemp(Ity_I64);
12424150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dLo     = newTemp(Ity_I64);
1242555085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = "???";
12426150c9cddb753ad4dc38f43484144523174d38b02sewardj      Int    laneszB = 0;
12427150c9cddb753ad4dc38f43484144523174d38b02sewardj
12428150c9cddb753ad4dc38f43484144523174d38b02sewardj      switch (insn[2]) {
12429150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x08: laneszB = 1; str = "b"; break;
12430150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x09: laneszB = 2; str = "w"; break;
12431150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x0A: laneszB = 4; str = "d"; break;
12432150c9cddb753ad4dc38f43484144523174d38b02sewardj         default: vassert(0);
12433150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12434150c9cddb753ad4dc38f43484144523174d38b02sewardj
12435150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12436150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
12437150c9cddb753ad4dc38f43484144523174d38b02sewardj
12438150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12439150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
12440150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12441150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("psign%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12442150c9cddb753ad4dc38f43484144523174d38b02sewardj                                     nameXMMReg(gregOfRM(modrm)));
12443150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12444150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12445150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12446150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12447150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12448150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("psign%s %s,%s\n", str, dis_buf,
12449150c9cddb753ad4dc38f43484144523174d38b02sewardj                                     nameXMMReg(gregOfRM(modrm)));
12450150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12451150c9cddb753ad4dc38f43484144523174d38b02sewardj
12452150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12453150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12454150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12455150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12456150c9cddb753ad4dc38f43484144523174d38b02sewardj
12457150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12458150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12459150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_64HLtoV128,
12460150c9cddb753ad4dc38f43484144523174d38b02sewardj               dis_PSIGN_helper( mkexpr(sHi), mkexpr(dHi), laneszB ),
12461150c9cddb753ad4dc38f43484144523174d38b02sewardj               dis_PSIGN_helper( mkexpr(sLo), mkexpr(dLo), laneszB )
12462150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12463150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12464150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12465150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12466150c9cddb753ad4dc38f43484144523174d38b02sewardj
12467150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 1C = PABSB -- Packed Absolute Value 8x8  (MMX) */
12468150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 1D = PABSW -- Packed Absolute Value 16x4 (MMX) */
12469150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 1E = PABSD -- Packed Absolute Value 32x2 (MMX) */
12470150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12471150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38
12472150c9cddb753ad4dc38f43484144523174d38b02sewardj       && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12473150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV      = newTemp(Ity_I64);
1247455085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = "???";
12475150c9cddb753ad4dc38f43484144523174d38b02sewardj      Int    laneszB = 0;
12476150c9cddb753ad4dc38f43484144523174d38b02sewardj
12477150c9cddb753ad4dc38f43484144523174d38b02sewardj      switch (insn[2]) {
12478150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x1C: laneszB = 1; str = "b"; break;
12479150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x1D: laneszB = 2; str = "w"; break;
12480150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x1E: laneszB = 4; str = "d"; break;
12481150c9cddb753ad4dc38f43484144523174d38b02sewardj         default: vassert(0);
12482150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12483150c9cddb753ad4dc38f43484144523174d38b02sewardj
12484150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12485150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12486150c9cddb753ad4dc38f43484144523174d38b02sewardj
12487150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12488150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12489150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12490150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pabs%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12491150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameMMXReg(gregOfRM(modrm)));
12492150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12493150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12494150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12495150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12496150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pabs%s %s,%s\n", str, dis_buf,
12497150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameMMXReg(gregOfRM(modrm)));
12498150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12499150c9cddb753ad4dc38f43484144523174d38b02sewardj
12500150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg(
12501150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12502150c9cddb753ad4dc38f43484144523174d38b02sewardj         dis_PABS_helper( mkexpr(sV), laneszB )
12503150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12504150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12505150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12506150c9cddb753ad4dc38f43484144523174d38b02sewardj
12507150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 1C = PABSB -- Packed Absolute Value 8x16 (XMM) */
12508150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 1D = PABSW -- Packed Absolute Value 16x8 (XMM) */
12509150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 1E = PABSD -- Packed Absolute Value 32x4 (XMM) */
12510150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12511150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38
12512150c9cddb753ad4dc38f43484144523174d38b02sewardj       && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12513150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV      = newTemp(Ity_V128);
12514150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sHi     = newTemp(Ity_I64);
12515150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sLo     = newTemp(Ity_I64);
1251655085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* str = "???";
12517150c9cddb753ad4dc38f43484144523174d38b02sewardj      Int    laneszB = 0;
12518150c9cddb753ad4dc38f43484144523174d38b02sewardj
12519150c9cddb753ad4dc38f43484144523174d38b02sewardj      switch (insn[2]) {
12520150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x1C: laneszB = 1; str = "b"; break;
12521150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x1D: laneszB = 2; str = "w"; break;
12522150c9cddb753ad4dc38f43484144523174d38b02sewardj         case 0x1E: laneszB = 4; str = "d"; break;
12523150c9cddb753ad4dc38f43484144523174d38b02sewardj         default: vassert(0);
12524150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12525150c9cddb753ad4dc38f43484144523174d38b02sewardj
12526150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12527150c9cddb753ad4dc38f43484144523174d38b02sewardj
12528150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12529150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
12530150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12531150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pabs%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12532150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameXMMReg(gregOfRM(modrm)));
12533150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12534150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12535150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12536150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12537150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12538150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pabs%s %s,%s\n", str, dis_buf,
12539150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameXMMReg(gregOfRM(modrm)));
12540150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12541150c9cddb753ad4dc38f43484144523174d38b02sewardj
12542150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12543150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12544150c9cddb753ad4dc38f43484144523174d38b02sewardj
12545150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12546150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12547150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_64HLtoV128,
12548150c9cddb753ad4dc38f43484144523174d38b02sewardj               dis_PABS_helper( mkexpr(sHi), laneszB ),
12549150c9cddb753ad4dc38f43484144523174d38b02sewardj               dis_PABS_helper( mkexpr(sLo), laneszB )
12550150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12551150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12552150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12553150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12554150c9cddb753ad4dc38f43484144523174d38b02sewardj
12555150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 3A 0F = PALIGNR -- Packed Align Right (MMX) */
12556150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12557150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12558150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV  = newTemp(Ity_I64);
12559150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV  = newTemp(Ity_I64);
12560150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp res = newTemp(Ity_I64);
12561150c9cddb753ad4dc38f43484144523174d38b02sewardj
12562150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12563150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12564150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
12565150c9cddb753ad4dc38f43484144523174d38b02sewardj
12566150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12567150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12568150c9cddb753ad4dc38f43484144523174d38b02sewardj         d32 = (UInt)insn[3+1];
12569150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1+1;
12570150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("palignr $%d,%s,%s\n",  (Int)d32,
12571150c9cddb753ad4dc38f43484144523174d38b02sewardj                                     nameMMXReg(eregOfRM(modrm)),
12572150c9cddb753ad4dc38f43484144523174d38b02sewardj                                     nameMMXReg(gregOfRM(modrm)));
12573150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12574150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12575150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12576150c9cddb753ad4dc38f43484144523174d38b02sewardj         d32 = (UInt)insn[3+alen];
12577150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen+1;
12578150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("palignr $%d%s,%s\n", (Int)d32,
12579150c9cddb753ad4dc38f43484144523174d38b02sewardj                                   dis_buf,
12580150c9cddb753ad4dc38f43484144523174d38b02sewardj                                   nameMMXReg(gregOfRM(modrm)));
12581150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12582150c9cddb753ad4dc38f43484144523174d38b02sewardj
12583150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (d32 == 0) {
12584150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( res, mkexpr(sV) );
12585150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12586150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 1 && d32 <= 7) {
12587150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign(res,
12588150c9cddb753ad4dc38f43484144523174d38b02sewardj                binop(Iop_Or64,
12589150c9cddb753ad4dc38f43484144523174d38b02sewardj                      binop(Iop_Shr64, mkexpr(sV), mkU8(8*d32)),
12590150c9cddb753ad4dc38f43484144523174d38b02sewardj                      binop(Iop_Shl64, mkexpr(dV), mkU8(8*(8-d32))
12591150c9cddb753ad4dc38f43484144523174d38b02sewardj                     )));
12592150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12593150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 == 8) {
12594150c9cddb753ad4dc38f43484144523174d38b02sewardj        assign( res, mkexpr(dV) );
12595150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12596150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 9 && d32 <= 15) {
12597150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( res, binop(Iop_Shr64, mkexpr(dV), mkU8(8*(d32-8))) );
12598150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12599150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 16 && d32 <= 255) {
12600150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( res, mkU64(0) );
12601150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12602150c9cddb753ad4dc38f43484144523174d38b02sewardj      else
12603150c9cddb753ad4dc38f43484144523174d38b02sewardj         vassert(0);
12604150c9cddb753ad4dc38f43484144523174d38b02sewardj
12605150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg( gregOfRM(modrm), mkexpr(res) );
12606150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12607150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12608150c9cddb753ad4dc38f43484144523174d38b02sewardj
12609150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 3A 0F = PALIGNR -- Packed Align Right (XMM) */
12610150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12611150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12612150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV  = newTemp(Ity_V128);
12613150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV  = newTemp(Ity_V128);
12614150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sHi = newTemp(Ity_I64);
12615150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sLo = newTemp(Ity_I64);
12616150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dHi = newTemp(Ity_I64);
12617150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dLo = newTemp(Ity_I64);
12618150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp rHi = newTemp(Ity_I64);
12619150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp rLo = newTemp(Ity_I64);
12620150c9cddb753ad4dc38f43484144523174d38b02sewardj
12621150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12622150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
12623150c9cddb753ad4dc38f43484144523174d38b02sewardj
12624150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12625150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
12626150c9cddb753ad4dc38f43484144523174d38b02sewardj         d32 = (UInt)insn[3+1];
12627150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1+1;
12628150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("palignr $%d,%s,%s\n", (Int)d32,
12629150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameXMMReg(eregOfRM(modrm)),
12630150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameXMMReg(gregOfRM(modrm)));
12631150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12632150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12633150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12634150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12635150c9cddb753ad4dc38f43484144523174d38b02sewardj         d32 = (UInt)insn[3+alen];
12636150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen+1;
12637150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("palignr $%d,%s,%s\n", (Int)d32,
12638150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    dis_buf,
12639150c9cddb753ad4dc38f43484144523174d38b02sewardj                                    nameXMMReg(gregOfRM(modrm)));
12640150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12641150c9cddb753ad4dc38f43484144523174d38b02sewardj
12642150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12643150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12644150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12645150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12646150c9cddb753ad4dc38f43484144523174d38b02sewardj
12647150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (d32 == 0) {
12648150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, mkexpr(sHi) );
12649150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, mkexpr(sLo) );
12650150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12651150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 1 && d32 <= 7) {
12652150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, dis_PALIGNR_XMM_helper(dLo, sHi, d32) );
12653150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, dis_PALIGNR_XMM_helper(sHi, sLo, d32) );
12654150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12655150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 == 8) {
12656150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, mkexpr(dLo) );
12657150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, mkexpr(sHi) );
12658150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12659150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 9 && d32 <= 15) {
12660150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, dis_PALIGNR_XMM_helper(dHi, dLo, d32-8) );
12661150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, dis_PALIGNR_XMM_helper(dLo, sHi, d32-8) );
12662150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12663150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 == 16) {
12664150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, mkexpr(dHi) );
12665150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, mkexpr(dLo) );
12666150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12667150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 17 && d32 <= 23) {
12668150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-16))) );
12669150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, dis_PALIGNR_XMM_helper(dHi, dLo, d32-16) );
12670150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12671150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 == 24) {
12672150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, mkU64(0) );
12673150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, mkexpr(dHi) );
12674150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12675150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 25 && d32 <= 31) {
12676150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, mkU64(0) );
12677150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-24))) );
12678150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12679150c9cddb753ad4dc38f43484144523174d38b02sewardj      else if (d32 >= 32 && d32 <= 255) {
12680150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rHi, mkU64(0) );
12681150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( rLo, mkU64(0) );
12682150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12683150c9cddb753ad4dc38f43484144523174d38b02sewardj      else
12684150c9cddb753ad4dc38f43484144523174d38b02sewardj         vassert(0);
12685150c9cddb753ad4dc38f43484144523174d38b02sewardj
12686150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12687150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12688150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12689150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12690150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12691150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12692150c9cddb753ad4dc38f43484144523174d38b02sewardj
12693150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x8 (MMX) */
12694150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 4
12695150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12696150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV      = newTemp(Ity_I64);
12697150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV      = newTemp(Ity_I64);
12698150c9cddb753ad4dc38f43484144523174d38b02sewardj
12699150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12700150c9cddb753ad4dc38f43484144523174d38b02sewardj      do_MMX_preamble();
12701150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getMMXReg(gregOfRM(modrm)) );
12702150c9cddb753ad4dc38f43484144523174d38b02sewardj
12703150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12704150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getMMXReg(eregOfRM(modrm)) );
12705150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12706150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pshufb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12707150c9cddb753ad4dc38f43484144523174d38b02sewardj                               nameMMXReg(gregOfRM(modrm)));
12708150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12709150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12710150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12711150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12712150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pshufb %s,%s\n", dis_buf,
12713150c9cddb753ad4dc38f43484144523174d38b02sewardj                               nameMMXReg(gregOfRM(modrm)));
12714150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12715150c9cddb753ad4dc38f43484144523174d38b02sewardj
12716150c9cddb753ad4dc38f43484144523174d38b02sewardj      putMMXReg(
12717150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12718150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(
12719150c9cddb753ad4dc38f43484144523174d38b02sewardj            Iop_And64,
12720150c9cddb753ad4dc38f43484144523174d38b02sewardj            /* permute the lanes */
12721150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(
12722150c9cddb753ad4dc38f43484144523174d38b02sewardj               Iop_Perm8x8,
12723150c9cddb753ad4dc38f43484144523174d38b02sewardj               mkexpr(dV),
12724150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_And64, mkexpr(sV), mkU64(0x0707070707070707ULL))
12725150c9cddb753ad4dc38f43484144523174d38b02sewardj            ),
12726150c9cddb753ad4dc38f43484144523174d38b02sewardj            /* mask off lanes which have (index & 0x80) == 0x80 */
12727150c9cddb753ad4dc38f43484144523174d38b02sewardj            unop(Iop_Not64, binop(Iop_SarN8x8, mkexpr(sV), mkU8(7)))
12728150c9cddb753ad4dc38f43484144523174d38b02sewardj         )
12729150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12730150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12731150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12732150c9cddb753ad4dc38f43484144523174d38b02sewardj
12733150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* 66 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x16 (XMM) */
12734150c9cddb753ad4dc38f43484144523174d38b02sewardj   if (sz == 2
12735150c9cddb753ad4dc38f43484144523174d38b02sewardj       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12736150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sV         = newTemp(Ity_V128);
12737150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dV         = newTemp(Ity_V128);
12738150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sHi        = newTemp(Ity_I64);
12739150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sLo        = newTemp(Ity_I64);
12740150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dHi        = newTemp(Ity_I64);
12741150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp dLo        = newTemp(Ity_I64);
12742150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp rHi        = newTemp(Ity_I64);
12743150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp rLo        = newTemp(Ity_I64);
12744150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sevens     = newTemp(Ity_I64);
12745150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp mask0x80hi = newTemp(Ity_I64);
12746150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp mask0x80lo = newTemp(Ity_I64);
12747150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp maskBit3hi = newTemp(Ity_I64);
12748150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp maskBit3lo = newTemp(Ity_I64);
12749150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sAnd7hi    = newTemp(Ity_I64);
12750150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp sAnd7lo    = newTemp(Ity_I64);
12751150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp permdHi    = newTemp(Ity_I64);
12752150c9cddb753ad4dc38f43484144523174d38b02sewardj      IRTemp permdLo    = newTemp(Ity_I64);
12753150c9cddb753ad4dc38f43484144523174d38b02sewardj
12754150c9cddb753ad4dc38f43484144523174d38b02sewardj      modrm = insn[3];
12755150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dV, getXMMReg(gregOfRM(modrm)) );
12756150c9cddb753ad4dc38f43484144523174d38b02sewardj
12757150c9cddb753ad4dc38f43484144523174d38b02sewardj      if (epartIsReg(modrm)) {
12758150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, getXMMReg(eregOfRM(modrm)) );
12759150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+1;
12760150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pshufb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12761150c9cddb753ad4dc38f43484144523174d38b02sewardj                               nameXMMReg(gregOfRM(modrm)));
12762150c9cddb753ad4dc38f43484144523174d38b02sewardj      } else {
12763150c9cddb753ad4dc38f43484144523174d38b02sewardj         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12764150c9cddb753ad4dc38f43484144523174d38b02sewardj         gen_SEGV_if_not_16_aligned( addr );
12765150c9cddb753ad4dc38f43484144523174d38b02sewardj         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12766150c9cddb753ad4dc38f43484144523174d38b02sewardj         delta += 3+alen;
12767150c9cddb753ad4dc38f43484144523174d38b02sewardj         DIP("pshufb %s,%s\n", dis_buf,
12768150c9cddb753ad4dc38f43484144523174d38b02sewardj                               nameXMMReg(gregOfRM(modrm)));
12769150c9cddb753ad4dc38f43484144523174d38b02sewardj      }
12770150c9cddb753ad4dc38f43484144523174d38b02sewardj
12771150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12772150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
12773150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12774150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
12775150c9cddb753ad4dc38f43484144523174d38b02sewardj
12776150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign( sevens, mkU64(0x0707070707070707ULL) );
12777150c9cddb753ad4dc38f43484144523174d38b02sewardj
12778150c9cddb753ad4dc38f43484144523174d38b02sewardj      /*
12779150c9cddb753ad4dc38f43484144523174d38b02sewardj      mask0x80hi = Not(SarN8x8(sHi,7))
12780150c9cddb753ad4dc38f43484144523174d38b02sewardj      maskBit3hi = SarN8x8(ShlN8x8(sHi,4),7)
12781150c9cddb753ad4dc38f43484144523174d38b02sewardj      sAnd7hi    = And(sHi,sevens)
12782150c9cddb753ad4dc38f43484144523174d38b02sewardj      permdHi    = Or( And(Perm8x8(dHi,sAnd7hi),maskBit3hi),
12783150c9cddb753ad4dc38f43484144523174d38b02sewardj                       And(Perm8x8(dLo,sAnd7hi),Not(maskBit3hi)) )
12784150c9cddb753ad4dc38f43484144523174d38b02sewardj      rHi        = And(permdHi,mask0x80hi)
12785150c9cddb753ad4dc38f43484144523174d38b02sewardj      */
12786150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(
12787150c9cddb753ad4dc38f43484144523174d38b02sewardj         mask0x80hi,
12788150c9cddb753ad4dc38f43484144523174d38b02sewardj         unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sHi),mkU8(7))));
12789150c9cddb753ad4dc38f43484144523174d38b02sewardj
12790150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(
12791150c9cddb753ad4dc38f43484144523174d38b02sewardj         maskBit3hi,
12792150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_SarN8x8,
12793150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_ShlN8x8,mkexpr(sHi),mkU8(4)),
12794150c9cddb753ad4dc38f43484144523174d38b02sewardj               mkU8(7)));
12795150c9cddb753ad4dc38f43484144523174d38b02sewardj
12796150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(sAnd7hi, binop(Iop_And64,mkexpr(sHi),mkexpr(sevens)));
12797150c9cddb753ad4dc38f43484144523174d38b02sewardj
12798150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(
12799150c9cddb753ad4dc38f43484144523174d38b02sewardj         permdHi,
12800150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(
12801150c9cddb753ad4dc38f43484144523174d38b02sewardj            Iop_Or64,
12802150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64,
12803150c9cddb753ad4dc38f43484144523174d38b02sewardj                  binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7hi)),
12804150c9cddb753ad4dc38f43484144523174d38b02sewardj                  mkexpr(maskBit3hi)),
12805150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64,
12806150c9cddb753ad4dc38f43484144523174d38b02sewardj                  binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7hi)),
12807150c9cddb753ad4dc38f43484144523174d38b02sewardj                  unop(Iop_Not64,mkexpr(maskBit3hi))) ));
12808150c9cddb753ad4dc38f43484144523174d38b02sewardj
12809150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(rHi, binop(Iop_And64,mkexpr(permdHi),mkexpr(mask0x80hi)) );
12810150c9cddb753ad4dc38f43484144523174d38b02sewardj
12811150c9cddb753ad4dc38f43484144523174d38b02sewardj      /* And the same for the lower half of the result.  What fun. */
12812150c9cddb753ad4dc38f43484144523174d38b02sewardj
12813150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(
12814150c9cddb753ad4dc38f43484144523174d38b02sewardj         mask0x80lo,
12815150c9cddb753ad4dc38f43484144523174d38b02sewardj         unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sLo),mkU8(7))));
12816150c9cddb753ad4dc38f43484144523174d38b02sewardj
12817150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(
12818150c9cddb753ad4dc38f43484144523174d38b02sewardj         maskBit3lo,
12819150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_SarN8x8,
12820150c9cddb753ad4dc38f43484144523174d38b02sewardj               binop(Iop_ShlN8x8,mkexpr(sLo),mkU8(4)),
12821150c9cddb753ad4dc38f43484144523174d38b02sewardj               mkU8(7)));
12822150c9cddb753ad4dc38f43484144523174d38b02sewardj
12823150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(sAnd7lo, binop(Iop_And64,mkexpr(sLo),mkexpr(sevens)));
12824150c9cddb753ad4dc38f43484144523174d38b02sewardj
12825150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(
12826150c9cddb753ad4dc38f43484144523174d38b02sewardj         permdLo,
12827150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(
12828150c9cddb753ad4dc38f43484144523174d38b02sewardj            Iop_Or64,
12829150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64,
12830150c9cddb753ad4dc38f43484144523174d38b02sewardj                  binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7lo)),
12831150c9cddb753ad4dc38f43484144523174d38b02sewardj                  mkexpr(maskBit3lo)),
12832150c9cddb753ad4dc38f43484144523174d38b02sewardj            binop(Iop_And64,
12833150c9cddb753ad4dc38f43484144523174d38b02sewardj                  binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7lo)),
12834150c9cddb753ad4dc38f43484144523174d38b02sewardj                  unop(Iop_Not64,mkexpr(maskBit3lo))) ));
12835150c9cddb753ad4dc38f43484144523174d38b02sewardj
12836150c9cddb753ad4dc38f43484144523174d38b02sewardj      assign(rLo, binop(Iop_And64,mkexpr(permdLo),mkexpr(mask0x80lo)) );
12837150c9cddb753ad4dc38f43484144523174d38b02sewardj
12838150c9cddb753ad4dc38f43484144523174d38b02sewardj      putXMMReg(
12839150c9cddb753ad4dc38f43484144523174d38b02sewardj         gregOfRM(modrm),
12840150c9cddb753ad4dc38f43484144523174d38b02sewardj         binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12841150c9cddb753ad4dc38f43484144523174d38b02sewardj      );
12842150c9cddb753ad4dc38f43484144523174d38b02sewardj      goto decode_success;
12843150c9cddb753ad4dc38f43484144523174d38b02sewardj   }
12844021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj
12845021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   /* 0F 38 F0 = MOVBE m16/32(E), r16/32(G) */
12846021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   /* 0F 38 F1 = MOVBE r16/32(G), m16/32(E) */
12847021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   if ((sz == 2 || sz == 4)
12848021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj       && insn[0] == 0x0F && insn[1] == 0x38
12849021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj       && (insn[2] == 0xF0 || insn[2] == 0xF1)
12850021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj       && !epartIsReg(insn[3])) {
12851021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj
12852021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      modrm = insn[3];
12853021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      addr = disAMode(&alen, sorb, delta + 3, dis_buf);
12854021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      delta += 3 + alen;
12855021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      ty = szToITy(sz);
12856021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      IRTemp src = newTemp(ty);
12857021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj
12858021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      if (insn[2] == 0xF0) { /* LOAD */
12859021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         assign(src, loadLE(ty, mkexpr(addr)));
12860021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         IRTemp dst = math_BSWAP(src, ty);
12861021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         putIReg(sz, gregOfRM(modrm), mkexpr(dst));
12862021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         DIP("movbe %s,%s\n", dis_buf, nameIReg(sz, gregOfRM(modrm)));
12863021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      } else { /* STORE */
12864021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         assign(src, getIReg(sz, gregOfRM(modrm)));
12865021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         IRTemp dst = math_BSWAP(src, ty);
12866021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         storeLE(mkexpr(addr), mkexpr(dst));
12867021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         DIP("movbe %s,%s\n", nameIReg(sz, gregOfRM(modrm)), dis_buf);
12868021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      }
12869021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj      goto decode_success;
12870021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj   }
12871150c9cddb753ad4dc38f43484144523174d38b02sewardj
12872150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* ---------------------------------------------------- */
12873150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* --- end of the SSSE3 decoder.                    --- */
12874150c9cddb753ad4dc38f43484144523174d38b02sewardj   /* ---------------------------------------------------- */
12875150c9cddb753ad4dc38f43484144523174d38b02sewardj
12876b72716141cdc951a57490a5745fcb498039936a8sewardj   /* ---------------------------------------------------- */
12877b72716141cdc951a57490a5745fcb498039936a8sewardj   /* --- start of the SSE4 decoder                    --- */
12878b72716141cdc951a57490a5745fcb498039936a8sewardj   /* ---------------------------------------------------- */
12879b72716141cdc951a57490a5745fcb498039936a8sewardj
12880b72716141cdc951a57490a5745fcb498039936a8sewardj   /* 66 0F 3A 0B /r ib = ROUNDSD imm8, xmm2/m64, xmm1
12881b72716141cdc951a57490a5745fcb498039936a8sewardj      (Partial implementation only -- only deal with cases where
12882b72716141cdc951a57490a5745fcb498039936a8sewardj      the rounding mode is specified directly by the immediate byte.)
12883b72716141cdc951a57490a5745fcb498039936a8sewardj      66 0F 3A 0A /r ib = ROUNDSS imm8, xmm2/m32, xmm1
12884b72716141cdc951a57490a5745fcb498039936a8sewardj      (Limitations ditto)
12885b72716141cdc951a57490a5745fcb498039936a8sewardj   */
12886b72716141cdc951a57490a5745fcb498039936a8sewardj   if (sz == 2
12887b72716141cdc951a57490a5745fcb498039936a8sewardj       && insn[0] == 0x0F && insn[1] == 0x3A
12888b72716141cdc951a57490a5745fcb498039936a8sewardj       && (/*insn[2] == 0x0B || */insn[2] == 0x0A)) {
12889b72716141cdc951a57490a5745fcb498039936a8sewardj
12890b72716141cdc951a57490a5745fcb498039936a8sewardj      Bool   isD = insn[2] == 0x0B;
12891b72716141cdc951a57490a5745fcb498039936a8sewardj      IRTemp src = newTemp(isD ? Ity_F64 : Ity_F32);
12892b72716141cdc951a57490a5745fcb498039936a8sewardj      IRTemp res = newTemp(isD ? Ity_F64 : Ity_F32);
12893b72716141cdc951a57490a5745fcb498039936a8sewardj      Int    imm = 0;
12894b72716141cdc951a57490a5745fcb498039936a8sewardj
12895b72716141cdc951a57490a5745fcb498039936a8sewardj      modrm = insn[3];
12896b72716141cdc951a57490a5745fcb498039936a8sewardj
12897b72716141cdc951a57490a5745fcb498039936a8sewardj      if (epartIsReg(modrm)) {
12898b72716141cdc951a57490a5745fcb498039936a8sewardj         assign( src,
12899b72716141cdc951a57490a5745fcb498039936a8sewardj                 isD ? getXMMRegLane64F( eregOfRM(modrm), 0 )
12900b72716141cdc951a57490a5745fcb498039936a8sewardj                     : getXMMRegLane32F( eregOfRM(modrm), 0 ) );
12901b72716141cdc951a57490a5745fcb498039936a8sewardj         imm = insn[3+1];
12902b72716141cdc951a57490a5745fcb498039936a8sewardj         if (imm & ~3) goto decode_failure;
12903b72716141cdc951a57490a5745fcb498039936a8sewardj         delta += 3+1+1;
12904b72716141cdc951a57490a5745fcb498039936a8sewardj         DIP( "rounds%c $%d,%s,%s\n",
12905b72716141cdc951a57490a5745fcb498039936a8sewardj              isD ? 'd' : 's',
12906b72716141cdc951a57490a5745fcb498039936a8sewardj              imm, nameXMMReg( eregOfRM(modrm) ),
12907b72716141cdc951a57490a5745fcb498039936a8sewardj                   nameXMMReg( gregOfRM(modrm) ) );
12908b72716141cdc951a57490a5745fcb498039936a8sewardj      } else {
12909b72716141cdc951a57490a5745fcb498039936a8sewardj         addr = disAMode( &alen, sorb, delta+3, dis_buf );
12910b72716141cdc951a57490a5745fcb498039936a8sewardj         assign( src, loadLE( isD ? Ity_F64 : Ity_F32, mkexpr(addr) ));
12911b72716141cdc951a57490a5745fcb498039936a8sewardj         imm = insn[3+alen];
12912b72716141cdc951a57490a5745fcb498039936a8sewardj         if (imm & ~3) goto decode_failure;
12913b72716141cdc951a57490a5745fcb498039936a8sewardj         delta += 3+alen+1;
12914b72716141cdc951a57490a5745fcb498039936a8sewardj         DIP( "roundsd $%d,%s,%s\n",
12915b72716141cdc951a57490a5745fcb498039936a8sewardj              imm, dis_buf, nameXMMReg( gregOfRM(modrm) ) );
12916b72716141cdc951a57490a5745fcb498039936a8sewardj      }
12917b72716141cdc951a57490a5745fcb498039936a8sewardj
12918b72716141cdc951a57490a5745fcb498039936a8sewardj      /* (imm & 3) contains an Intel-encoded rounding mode.  Because
12919b72716141cdc951a57490a5745fcb498039936a8sewardj         that encoding is the same as the encoding for IRRoundingMode,
12920b72716141cdc951a57490a5745fcb498039936a8sewardj         we can use that value directly in the IR as a rounding
12921b72716141cdc951a57490a5745fcb498039936a8sewardj         mode. */
12922b72716141cdc951a57490a5745fcb498039936a8sewardj      assign(res, binop(isD ? Iop_RoundF64toInt : Iop_RoundF32toInt,
12923b72716141cdc951a57490a5745fcb498039936a8sewardj                  mkU32(imm & 3), mkexpr(src)) );
12924b72716141cdc951a57490a5745fcb498039936a8sewardj
12925b72716141cdc951a57490a5745fcb498039936a8sewardj      if (isD)
12926b72716141cdc951a57490a5745fcb498039936a8sewardj         putXMMRegLane64F( gregOfRM(modrm), 0, mkexpr(res) );
12927b72716141cdc951a57490a5745fcb498039936a8sewardj      else
12928b72716141cdc951a57490a5745fcb498039936a8sewardj         putXMMRegLane32F( gregOfRM(modrm), 0, mkexpr(res) );
12929b72716141cdc951a57490a5745fcb498039936a8sewardj
12930b72716141cdc951a57490a5745fcb498039936a8sewardj      goto decode_success;
12931b72716141cdc951a57490a5745fcb498039936a8sewardj   }
12932b72716141cdc951a57490a5745fcb498039936a8sewardj
12933536fbabcc3770f42bb7370efd75e8e30e9a841c8sewardj   /* F3 0F BD -- LZCNT (count leading zeroes.  An AMD extension,
12934536fbabcc3770f42bb7370efd75e8e30e9a841c8sewardj      which we can only decode if we're sure this is an AMD cpu that
12935536fbabcc3770f42bb7370efd75e8e30e9a841c8sewardj      supports LZCNT, since otherwise it's BSR, which behaves
12936536fbabcc3770f42bb7370efd75e8e30e9a841c8sewardj      differently. */
12937536fbabcc3770f42bb7370efd75e8e30e9a841c8sewardj   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xBD
12938536fbabcc3770f42bb7370efd75e8e30e9a841c8sewardj       && 0 != (archinfo->hwcaps & VEX_HWCAPS_X86_LZCNT)) {
129399a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      vassert(sz == 2 || sz == 4);
129409a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      /*IRType*/ ty  = szToITy(sz);
129419a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      IRTemp     src = newTemp(ty);
129429a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      modrm = insn[3];
129439a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      if (epartIsReg(modrm)) {
129449a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         assign(src, getIReg(sz, eregOfRM(modrm)));
129459a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         delta += 3+1;
129469a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         DIP("lzcnt%c %s, %s\n", nameISize(sz),
129479a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj             nameIReg(sz, eregOfRM(modrm)),
129489a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj             nameIReg(sz, gregOfRM(modrm)));
129499a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      } else {
129509a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         addr = disAMode( &alen, sorb, delta+3, dis_buf );
129519a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         assign(src, loadLE(ty, mkexpr(addr)));
129529a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         delta += 3+alen;
129539a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         DIP("lzcnt%c %s, %s\n", nameISize(sz), dis_buf,
129549a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj             nameIReg(sz, gregOfRM(modrm)));
129559a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      }
129569a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
129579a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      IRTemp res = gen_LZCNT(ty, src);
129589a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      putIReg(sz, gregOfRM(modrm), mkexpr(res));
129599a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
129609a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      // Update flags.  This is pretty lame .. perhaps can do better
129619a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      // if this turns out to be performance critical.
129629a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      // O S A P are cleared.  Z is set if RESULT == 0.
129639a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      // C is set if SRC is zero.
129649a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      IRTemp src32 = newTemp(Ity_I32);
129659a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      IRTemp res32 = newTemp(Ity_I32);
129669a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      assign(src32, widenUto32(mkexpr(src)));
129679a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      assign(res32, widenUto32(mkexpr(res)));
129689a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
129699a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      IRTemp oszacp = newTemp(Ity_I32);
129709a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      assign(
129719a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         oszacp,
129729a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         binop(Iop_Or32,
129739a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj               binop(Iop_Shl32,
129749a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                     unop(Iop_1Uto32,
129759a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                          binop(Iop_CmpEQ32, mkexpr(res32), mkU32(0))),
129769a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                     mkU8(X86G_CC_SHIFT_Z)),
129779a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj               binop(Iop_Shl32,
129789a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                     unop(Iop_1Uto32,
129799a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                          binop(Iop_CmpEQ32, mkexpr(src32), mkU32(0))),
129809a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj                     mkU8(X86G_CC_SHIFT_C))
129819a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj         )
129829a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      );
129839a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
129849a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
129859a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
129869a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
129879a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(oszacp) ));
129889a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
129899a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj      goto decode_success;
129909a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj   }
129919a660ea5bddd117a6f19d9423b3bc96d01031a9bsewardj
12992b72716141cdc951a57490a5745fcb498039936a8sewardj   /* ---------------------------------------------------- */
12993b72716141cdc951a57490a5745fcb498039936a8sewardj   /* --- end of the SSE4 decoder                      --- */
12994b72716141cdc951a57490a5745fcb498039936a8sewardj   /* ---------------------------------------------------- */
12995b72716141cdc951a57490a5745fcb498039936a8sewardj
129969df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj   after_sse_decoders:
129979df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj
12998dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* ---------------------------------------------------- */
12999dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* --- deal with misc 0x67 pfxs (addr size override) -- */
13000dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* ---------------------------------------------------- */
13001dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj
13002dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* 67 E3 = JCXZ (for JECXZ see below) */
13003dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   if (insn[0] == 0x67 && insn[1] == 0xE3 && sz == 4) {
13004dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj      delta += 2;
13005dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13006dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj      delta ++;
13007dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj      stmt( IRStmt_Exit(
13008dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj               binop(Iop_CmpEQ16, getIReg(2,R_ECX), mkU16(0)),
13009dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj               Ijk_Boring,
13010c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj               IRConst_U32(d32),
13011c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj               OFFB_EIP
13012dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj            ));
13013dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj       DIP("jcxz 0x%x\n", d32);
13014dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj       goto decode_success;
13015dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   }
13016dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj
13017dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* ---------------------------------------------------- */
13018dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* --- start of the baseline insn decoder            -- */
13019dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   /* ---------------------------------------------------- */
13020dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj
13021c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* Get the primary opcode. */
13022c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   opc = getIByte(delta); delta++;
13023c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
13024c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* We get here if the current insn isn't SSE, or this CPU doesn't
13025c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      support SSE. */
13026c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
13027c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   switch (opc) {
13028c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
13029c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* ------------------------ Control flow --------------- */
13030940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
13031940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   case 0xC2: /* RET imm16 */
13032940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      d32 = getUDisp16(delta);
13033940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      delta += 2;
13034c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      dis_ret(&dres, d32);
130352d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj      DIP("ret %d\n", (Int)d32);
13036940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
13037e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   case 0xC3: /* RET */
13038c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      dis_ret(&dres, 0);
13039e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      DIP("ret\n");
13040e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
130410e9a0f551e190b475150dcd6bc4500033eb05338sewardj
130420e9a0f551e190b475150dcd6bc4500033eb05338sewardj   case 0xCF: /* IRET */
130430e9a0f551e190b475150dcd6bc4500033eb05338sewardj      /* Note, this is an extremely kludgey and limited implementation
130440e9a0f551e190b475150dcd6bc4500033eb05338sewardj         of iret.  All it really does is:
130450e9a0f551e190b475150dcd6bc4500033eb05338sewardj            popl %EIP; popl %CS; popl %EFLAGS.
130460e9a0f551e190b475150dcd6bc4500033eb05338sewardj         %CS is set but ignored (as it is in (eg) popw %cs)". */
130470e9a0f551e190b475150dcd6bc4500033eb05338sewardj      t1 = newTemp(Ity_I32); /* ESP */
130480e9a0f551e190b475150dcd6bc4500033eb05338sewardj      t2 = newTemp(Ity_I32); /* new EIP */
130490e9a0f551e190b475150dcd6bc4500033eb05338sewardj      t3 = newTemp(Ity_I32); /* new CS */
130500e9a0f551e190b475150dcd6bc4500033eb05338sewardj      t4 = newTemp(Ity_I32); /* new EFLAGS */
130510e9a0f551e190b475150dcd6bc4500033eb05338sewardj      assign(t1, getIReg(4,R_ESP));
130520e9a0f551e190b475150dcd6bc4500033eb05338sewardj      assign(t2, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(0) )));
130530e9a0f551e190b475150dcd6bc4500033eb05338sewardj      assign(t3, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(4) )));
130540e9a0f551e190b475150dcd6bc4500033eb05338sewardj      assign(t4, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(8) )));
130550e9a0f551e190b475150dcd6bc4500033eb05338sewardj      /* Get stuff off stack */
130560e9a0f551e190b475150dcd6bc4500033eb05338sewardj      putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(12)));
130570e9a0f551e190b475150dcd6bc4500033eb05338sewardj      /* set %CS (which is ignored anyway) */
130580e9a0f551e190b475150dcd6bc4500033eb05338sewardj      putSReg( R_CS, unop(Iop_32to16, mkexpr(t3)) );
130590e9a0f551e190b475150dcd6bc4500033eb05338sewardj      /* set %EFLAGS */
130600e9a0f551e190b475150dcd6bc4500033eb05338sewardj      set_EFLAGS_from_value( t4, False/*!emit_AC_emwarn*/, 0/*unused*/ );
130610e9a0f551e190b475150dcd6bc4500033eb05338sewardj      /* goto new EIP value */
13062c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      jmp_treg(&dres, Ijk_Ret, t2);
13063c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      vassert(dres.whatNext == Dis_StopHere);
130640e9a0f551e190b475150dcd6bc4500033eb05338sewardj      DIP("iret (very kludgey)\n");
130650e9a0f551e190b475150dcd6bc4500033eb05338sewardj      break;
130660e9a0f551e190b475150dcd6bc4500033eb05338sewardj
13067d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0xE8: /* CALL J4 */
13068d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      d32 = getUDisp32(delta); delta += 4;
130699e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj      d32 += (guest_EIP_bbstart+delta);
13070ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj      /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
130719e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj      if (d32 == guest_EIP_bbstart+delta && getIByte(delta) >= 0x58
13072ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj                                         && getIByte(delta) <= 0x5F) {
13073d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         /* Specially treat the position-independent-code idiom
13074d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                 call X
13075d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj              X: popl %reg
13076d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            as
13077d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj                 movl %eip, %reg.
13078d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj            since this generates better code, but for no other reason. */
13079d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         Int archReg = getIByte(delta) - 0x58;
13080c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         /* vex_printf("-- fPIC thingy\n"); */
130819e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj         putIReg(4, archReg, mkU32(guest_EIP_bbstart+delta));
13082d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         delta++; /* Step over the POP */
13083d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
13084c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      } else {
13085d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         /* The normal sequence for a call. */
13086d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         t1 = newTemp(Ity_I32);
1308741f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj         assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
1308841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj         putIReg(4, R_ESP, mkexpr(t1));
130899e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj         storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
13090beac530a718fcc646bc61fe60a86f599df54e1d7florian         if (resteerOkFn( callback_opaque, (Addr32)d32 )) {
13091ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj            /* follow into the call target. */
13092984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            dres.whatNext   = Dis_ResteerU;
130930eaa35ff5569f09129073be27c2f827926f7010dflorian            dres.continueAt = (Addr32)d32;
13094ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj         } else {
13095c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jmp_lit(&dres, Ijk_Call, d32);
13096c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres.whatNext == Dis_StopHere);
13097ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj         }
13098d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         DIP("call 0x%x\n",d32);
13099d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      }
13100d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      break;
13101d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
13102c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--    case 0xC8: /* ENTER */
13103c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       d32 = getUDisp16(eip); eip += 2;
13104c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       abyte = getIByte(delta); delta++;
13105c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
13106c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       vg_assert(sz == 4);
13107c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       vg_assert(abyte == 0);
13108c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
13109c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       t1 = newTemp(cb); t2 = newTemp(cb);
13110c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr2(cb, GET,   sz, ArchReg, R_EBP, TempReg, t1);
13111c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr2(cb, GET,    4, ArchReg, R_ESP, TempReg, t2);
13112c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr2(cb, SUB,    4, Literal, 0,     TempReg, t2);
13113c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uLiteral(cb, sz);
13114c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_ESP);
13115c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr2(cb, STORE,  4, TempReg, t1,    TempReg, t2);
13116c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_EBP);
13117c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       if (d32) {
13118c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, SUB,    4, Literal, 0,     TempReg, t2);
131195bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj//--          uLiteral(cb, d32);
131205bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj//--          uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_ESP);
13121c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       }
13122c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       DIP("enter 0x%x, 0x%x", d32, abyte);
13123c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       break;
13124c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
13125c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xC9: /* LEAVE */
13126c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      vassert(sz == 4);
13127c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13128c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      assign(t1, getIReg(4,R_EBP));
13129c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      /* First PUT ESP looks redundant, but need it because ESP must
13130c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj         always be up-to-date for Memcheck to work... */
13131c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      putIReg(4, R_ESP, mkexpr(t1));
13132c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      assign(t2, loadLE(Ity_I32,mkexpr(t1)));
13133c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      putIReg(4, R_EBP, mkexpr(t2));
13134c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
13135c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      DIP("leave\n");
13136c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
13137c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
131388edc36b45e95a7ec9879a25b80390129f1d334c1sewardj   /* ---------------- Misc weird-ass insns --------------- */
131398edc36b45e95a7ec9879a25b80390129f1d334c1sewardj
131408edc36b45e95a7ec9879a25b80390129f1d334c1sewardj   case 0x27: /* DAA */
131418edc36b45e95a7ec9879a25b80390129f1d334c1sewardj   case 0x2F: /* DAS */
131428edc36b45e95a7ec9879a25b80390129f1d334c1sewardj   case 0x37: /* AAA */
131438edc36b45e95a7ec9879a25b80390129f1d334c1sewardj   case 0x3F: /* AAS */
131448edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      /* An ugly implementation for some ugly instructions.  Oh
131458edc36b45e95a7ec9879a25b80390129f1d334c1sewardj	 well. */
131468edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      if (sz != 4) goto decode_failure;
131478edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      t1 = newTemp(Ity_I32);
131488edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      t2 = newTemp(Ity_I32);
131498edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      /* Make up a 32-bit value (t1), with the old value of AX in the
131508edc36b45e95a7ec9879a25b80390129f1d334c1sewardj         bottom 16 bits, and the old OSZACP bitmask in the upper 16
131518edc36b45e95a7ec9879a25b80390129f1d334c1sewardj         bits. */
131528edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      assign(t1,
131538edc36b45e95a7ec9879a25b80390129f1d334c1sewardj             binop(Iop_16HLto32,
131548edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                   unop(Iop_32to16,
131558edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                        mk_x86g_calculate_eflags_all()),
131568edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                   getIReg(2, R_EAX)
131578edc36b45e95a7ec9879a25b80390129f1d334c1sewardj            ));
131588edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      /* Call the helper fn, to get a new AX and OSZACP value, and
131598edc36b45e95a7ec9879a25b80390129f1d334c1sewardj         poke both back into the guest state.  Also pass the helper
131608edc36b45e95a7ec9879a25b80390129f1d334c1sewardj         the actual opcode so it knows which of the 4 instructions it
131618edc36b45e95a7ec9879a25b80390129f1d334c1sewardj         is doing the computation for. */
131628edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      vassert(opc == 0x27 || opc == 0x2F || opc == 0x37 || opc == 0x3F);
131638edc36b45e95a7ec9879a25b80390129f1d334c1sewardj      assign(t2,
131648edc36b45e95a7ec9879a25b80390129f1d334c1sewardj              mkIRExprCCall(
131658edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                 Ity_I32, 0/*regparm*/, "x86g_calculate_daa_das_aaa_aas",
131668edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                 &x86g_calculate_daa_das_aaa_aas,
131678edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
131688edc36b45e95a7ec9879a25b80390129f1d334c1sewardj            ));
131698edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
131708edc36b45e95a7ec9879a25b80390129f1d334c1sewardj
131718edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
131728edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
131738edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     stmt( IRStmt_Put( OFFB_CC_DEP1,
131748edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                       binop(Iop_And32,
131758edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                             binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
131768edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                             mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
131778edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                                    | X86G_CC_MASK_A | X86G_CC_MASK_Z
131788edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                                    | X86G_CC_MASK_S| X86G_CC_MASK_O )
131798edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                            )
131808edc36b45e95a7ec9879a25b80390129f1d334c1sewardj                      )
131818edc36b45e95a7ec9879a25b80390129f1d334c1sewardj         );
131828edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     /* Set NDEP even though it isn't used.  This makes redundant-PUT
131838edc36b45e95a7ec9879a25b80390129f1d334c1sewardj        elimination of previous stores to this field work better. */
131848edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
131858edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     switch (opc) {
131868edc36b45e95a7ec9879a25b80390129f1d334c1sewardj        case 0x27: DIP("daa\n"); break;
131878edc36b45e95a7ec9879a25b80390129f1d334c1sewardj        case 0x2F: DIP("das\n"); break;
131888edc36b45e95a7ec9879a25b80390129f1d334c1sewardj        case 0x37: DIP("aaa\n"); break;
131898edc36b45e95a7ec9879a25b80390129f1d334c1sewardj        case 0x3F: DIP("aas\n"); break;
131908edc36b45e95a7ec9879a25b80390129f1d334c1sewardj        default: vassert(0);
131918edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     }
131928edc36b45e95a7ec9879a25b80390129f1d334c1sewardj     break;
131938edc36b45e95a7ec9879a25b80390129f1d334c1sewardj
13194321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj   case 0xD4: /* AAM */
13195321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj   case 0xD5: /* AAD */
13196321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      d32 = getIByte(delta); delta++;
13197321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      if (sz != 4 || d32 != 10) goto decode_failure;
13198321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      t1 = newTemp(Ity_I32);
13199321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      t2 = newTemp(Ity_I32);
13200321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      /* Make up a 32-bit value (t1), with the old value of AX in the
13201321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         bottom 16 bits, and the old OSZACP bitmask in the upper 16
13202321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         bits. */
13203321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      assign(t1,
13204321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj             binop(Iop_16HLto32,
13205321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                   unop(Iop_32to16,
13206321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                        mk_x86g_calculate_eflags_all()),
13207321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                   getIReg(2, R_EAX)
13208321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj            ));
13209321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      /* Call the helper fn, to get a new AX and OSZACP value, and
13210321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         poke both back into the guest state.  Also pass the helper
13211321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         the actual opcode so it knows which of the 2 instructions it
13212321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         is doing the computation for. */
13213321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      assign(t2,
13214321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj              mkIRExprCCall(
13215321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                 Ity_I32, 0/*regparm*/, "x86g_calculate_aad_aam",
13216321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                 &x86g_calculate_aad_aam,
13217321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
13218321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj            ));
13219321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
13220321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj
13221321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
13222321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13223321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      stmt( IRStmt_Put( OFFB_CC_DEP1,
13224321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                        binop(Iop_And32,
13225321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                              binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
13226321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                              mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
13227321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                                     | X86G_CC_MASK_A | X86G_CC_MASK_Z
13228321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                                     | X86G_CC_MASK_S| X86G_CC_MASK_O )
13229321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                             )
13230321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj                       )
13231321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj          );
13232321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      /* Set NDEP even though it isn't used.  This makes
13233321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         redundant-PUT elimination of previous stores to this field
13234321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj         work better. */
13235321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13236321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj
13237321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      DIP(opc == 0xD4 ? "aam\n" : "aad\n");
13238321bbbf4a200e69496eb0a48506d3b67a1cdbbdbsewardj      break;
132391c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
132401c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* ------------------------ CWD/CDQ -------------------- */
132411c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
132421c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   case 0x98: /* CBW */
132431c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      if (sz == 4) {
132441c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj         putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
132451c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj         DIP("cwde\n");
132461c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      } else {
1324747341042b1b4140b5b4b42983df7bec015f7beecsewardj         vassert(sz == 2);
1324847341042b1b4140b5b4b42983df7bec015f7beecsewardj         putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
1324947341042b1b4140b5b4b42983df7bec015f7beecsewardj         DIP("cbw\n");
132501c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      }
132511c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      break;
1325264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1325364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x99: /* CWD/CDQ */
1325464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      ty = szToITy(sz);
1325564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      putIReg(sz, R_EDX,
1325664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj                  binop(mkSizedOp(ty,Iop_Sar8),
1325764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj                        getIReg(sz, R_EAX),
132589ee8286c3e2b42ca93acf74726f8668ee98d4b08sewardj                        mkU8(sz == 2 ? 15 : 31)) );
1325964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
1326064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      break;
1326164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
13262bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   /* ------------------------ FPU ops -------------------- */
13263bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
13264bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   case 0x9E: /* SAHF */
13265bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      codegen_SAHF();
13266bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      DIP("sahf\n");
13267bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      break;
13268bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
132698dfdc8a059e35940fe96371360cae39d9724cea9sewardj   case 0x9F: /* LAHF */
132708dfdc8a059e35940fe96371360cae39d9724cea9sewardj      codegen_LAHF();
132718dfdc8a059e35940fe96371360cae39d9724cea9sewardj      DIP("lahf\n");
132728dfdc8a059e35940fe96371360cae39d9724cea9sewardj      break;
132738dfdc8a059e35940fe96371360cae39d9724cea9sewardj
13274bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj   case 0x9B: /* FWAIT */
13275bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      /* ignore? */
13276bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      DIP("fwait\n");
13277bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj      break;
13278bdc7d215ca35fbf5213549560fc3bd8967f60f6dsewardj
13279d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xD8:
13280d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xD9:
13281d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xDA:
13282d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xDB:
13283d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xDC:
13284d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xDD:
13285d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xDE:
13286d1725d18b61bf7912a9099686179faef5815dba1sewardj   case 0xDF: {
1328752d049186d07991237a825ec88aa7f1f303edb70sewardj      Int  delta0    = delta;
13288d1725d18b61bf7912a9099686179faef5815dba1sewardj      Bool decode_OK = False;
13289d1725d18b61bf7912a9099686179faef5815dba1sewardj      delta = dis_FPU ( &decode_OK, sorb, delta );
13290d1725d18b61bf7912a9099686179faef5815dba1sewardj      if (!decode_OK) {
13291d1725d18b61bf7912a9099686179faef5815dba1sewardj         delta = delta0;
13292d1725d18b61bf7912a9099686179faef5815dba1sewardj         goto decode_failure;
13293d1725d18b61bf7912a9099686179faef5815dba1sewardj      }
13294d1725d18b61bf7912a9099686179faef5815dba1sewardj      break;
13295d1725d18b61bf7912a9099686179faef5815dba1sewardj   }
132960611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
132970611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   /* ------------------------ INC & DEC ------------------ */
132980611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
132990611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x40: /* INC eAX */
133000611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x41: /* INC eCX */
133010611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x42: /* INC eDX */
133020611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x43: /* INC eBX */
133030611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x44: /* INC eSP */
133040611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x45: /* INC eBP */
133050611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x46: /* INC eSI */
133060611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x47: /* INC eDI */
133070611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      vassert(sz == 2 || sz == 4);
133080611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      ty = szToITy(sz);
133090611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      t1 = newTemp(ty);
133100611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      assign( t1, binop(mkSizedOp(ty,Iop_Add8),
133110611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                        getIReg(sz, (UInt)(opc - 0x40)),
133120611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                        mkU(ty,1)) );
133130611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      setFlags_INC_DEC( True, t1, ty );
133140611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
133150611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
133160611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
133170611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
133180611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x48: /* DEC eAX */
133190611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x49: /* DEC eCX */
133200611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x4A: /* DEC eDX */
133210611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x4B: /* DEC eBX */
133220611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x4C: /* DEC eSP */
133230611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x4D: /* DEC eBP */
133240611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x4E: /* DEC eSI */
133250611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x4F: /* DEC eDI */
133260611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      vassert(sz == 2 || sz == 4);
133270611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      ty = szToITy(sz);
133280611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      t1 = newTemp(ty);
133290611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
133300611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                        getIReg(sz, (UInt)(opc - 0x48)),
133310611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                        mkU(ty,1)) );
133320611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      setFlags_INC_DEC( False, t1, ty );
133330611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
133340611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
133350611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
133360611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
133370611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   /* ------------------------ INT ------------------------ */
133380611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
13339322bfa0201be78c22f1ec1d579355bd2a7ac51aesewardj   case 0xCC: /* INT 3 */
13340c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      jmp_lit(&dres, Ijk_SigTRAP, ((Addr32)guest_EIP_bbstart)+delta);
13341c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      vassert(dres.whatNext == Dis_StopHere);
13342322bfa0201be78c22f1ec1d579355bd2a7ac51aesewardj      DIP("int $0x3\n");
13343322bfa0201be78c22f1ec1d579355bd2a7ac51aesewardj      break;
13344322bfa0201be78c22f1ec1d579355bd2a7ac51aesewardj
133450611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0xCD: /* INT imm8 */
133460611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      d32 = getIByte(delta); delta++;
133470f50004eefdf1066682a016efb4a57c092ae2da2sewardj
13348d660d41d4174e44f284bad3264601662ed68d4a1sewardj      /* For any of the cases where we emit a jump (that is, for all
13349d660d41d4174e44f284bad3264601662ed68d4a1sewardj         currently handled cases), it's important that all ArchRegs
13350d660d41d4174e44f284bad3264601662ed68d4a1sewardj         carry their up-to-date value at this point.  So we declare an
13351d660d41d4174e44f284bad3264601662ed68d4a1sewardj         end-of-block here, which forces any TempRegs caching ArchRegs
13352d660d41d4174e44f284bad3264601662ed68d4a1sewardj         to be flushed. */
13353d660d41d4174e44f284bad3264601662ed68d4a1sewardj
1335484af676f5b09efab952869c755bc5cdb7468e55bsewardj      /* Handle int $0x3F .. $0x4F by synthesising a segfault and a
133550f50004eefdf1066682a016efb4a57c092ae2da2sewardj         restart of this instruction (hence the "-2" two lines below,
133560f50004eefdf1066682a016efb4a57c092ae2da2sewardj         to get the restart EIP to be this instruction.  This is
133570f50004eefdf1066682a016efb4a57c092ae2da2sewardj         probably Linux-specific and it would be more correct to only
1335884af676f5b09efab952869c755bc5cdb7468e55bsewardj         do this if the VexAbiInfo says that is what we should do.
1335984af676f5b09efab952869c755bc5cdb7468e55bsewardj         This used to handle just 0x40-0x43; Jikes RVM uses a larger
1336084af676f5b09efab952869c755bc5cdb7468e55bsewardj         range (0x3F-0x49), and this allows some slack as well. */
1336184af676f5b09efab952869c755bc5cdb7468e55bsewardj      if (d32 >= 0x3F && d32 <= 0x4F) {
13362c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jmp_lit(&dres, Ijk_SigSEGV, ((Addr32)guest_EIP_bbstart)+delta-2);
13363c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
133640f50004eefdf1066682a016efb4a57c092ae2da2sewardj         DIP("int $0x%x\n", (Int)d32);
133650f50004eefdf1066682a016efb4a57c092ae2da2sewardj         break;
133660f50004eefdf1066682a016efb4a57c092ae2da2sewardj      }
133670f50004eefdf1066682a016efb4a57c092ae2da2sewardj
13368d660d41d4174e44f284bad3264601662ed68d4a1sewardj      /* Handle int $0x80 (linux syscalls), int $0x81 and $0x82
13369e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         (darwin syscalls).  As part of this, note where we are, so we
13370e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         can back up the guest to this point if the syscall needs to
13371e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         be restarted. */
13372d660d41d4174e44f284bad3264601662ed68d4a1sewardj      if (d32 == 0x80) {
13373e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13374e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj                           mkU32(guest_EIP_curr_instr) ) );
13375c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jmp_lit(&dres, Ijk_Sys_int128, ((Addr32)guest_EIP_bbstart)+delta);
13376c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
13377d660d41d4174e44f284bad3264601662ed68d4a1sewardj         DIP("int $0x80\n");
13378d660d41d4174e44f284bad3264601662ed68d4a1sewardj         break;
13379d660d41d4174e44f284bad3264601662ed68d4a1sewardj      }
13380d660d41d4174e44f284bad3264601662ed68d4a1sewardj      if (d32 == 0x81) {
13381e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13382e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj                           mkU32(guest_EIP_curr_instr) ) );
13383c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jmp_lit(&dres, Ijk_Sys_int129, ((Addr32)guest_EIP_bbstart)+delta);
13384c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
13385d660d41d4174e44f284bad3264601662ed68d4a1sewardj         DIP("int $0x81\n");
13386d660d41d4174e44f284bad3264601662ed68d4a1sewardj         break;
13387d660d41d4174e44f284bad3264601662ed68d4a1sewardj      }
13388d660d41d4174e44f284bad3264601662ed68d4a1sewardj      if (d32 == 0x82) {
13389e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13390e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj                           mkU32(guest_EIP_curr_instr) ) );
13391c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jmp_lit(&dres, Ijk_Sys_int130, ((Addr32)guest_EIP_bbstart)+delta);
13392c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
13393d660d41d4174e44f284bad3264601662ed68d4a1sewardj         DIP("int $0x82\n");
13394d660d41d4174e44f284bad3264601662ed68d4a1sewardj         break;
13395d660d41d4174e44f284bad3264601662ed68d4a1sewardj      }
13396d660d41d4174e44f284bad3264601662ed68d4a1sewardj
13397d660d41d4174e44f284bad3264601662ed68d4a1sewardj      /* none of the above */
13398d660d41d4174e44f284bad3264601662ed68d4a1sewardj      goto decode_failure;
133990611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
1340077b86be374085943e902075b305ff047a053aac6sewardj   /* ------------------------ Jcond, byte offset --------- */
1340177b86be374085943e902075b305ff047a053aac6sewardj
1340277b86be374085943e902075b305ff047a053aac6sewardj   case 0xEB: /* Jb (jump, byte offset) */
134039e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
1340477b86be374085943e902075b305ff047a053aac6sewardj      delta++;
13405beac530a718fcc646bc61fe60a86f599df54e1d7florian      if (resteerOkFn( callback_opaque, (Addr32)d32) ) {
13406984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         dres.whatNext   = Dis_ResteerU;
134070eaa35ff5569f09129073be27c2f827926f7010dflorian         dres.continueAt = (Addr32)d32;
13408ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj      } else {
13409c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jmp_lit(&dres, Ijk_Boring, d32);
13410c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
13411ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj      }
1341277b86be374085943e902075b305ff047a053aac6sewardj      DIP("jmp-8 0x%x\n", d32);
1341377b86be374085943e902075b305ff047a053aac6sewardj      break;
134140611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
134150611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0xE9: /* Jv (jump, 16/32 offset) */
134160611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      vassert(sz == 4); /* JRS added 2004 July 11 */
134179e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj      d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta);
134180611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      delta += sz;
13419beac530a718fcc646bc61fe60a86f599df54e1d7florian      if (resteerOkFn( callback_opaque, (Addr32)d32) ) {
13420984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         dres.whatNext   = Dis_ResteerU;
134210eaa35ff5569f09129073be27c2f827926f7010dflorian         dres.continueAt = (Addr32)d32;
13422ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj      } else {
13423c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jmp_lit(&dres, Ijk_Boring, d32);
13424c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
13425ce70a5c1c05704c9ea655abbcdf2c39c1d788d65sewardj      }
134260611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      DIP("jmp 0x%x\n", d32);
134270611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
13428e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
13429e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x70:
13430e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x71:
13431e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x72: /* JBb/JNAEb (jump below) */
13432e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x73: /* JNBb/JAEb (jump not below) */
13433e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x74: /* JZb/JEb (jump zero) */
13434e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x75: /* JNZb/JNEb (jump not zero) */
13435e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x76: /* JBEb/JNAb (jump below or equal) */
13436e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x77: /* JNBEb/JAb (jump not below or equal) */
13437e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x78: /* JSb (jump negative) */
13438e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x79: /* JSb (jump not negative) */
13439e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x7A: /* JP (jump parity even) */
13440e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x7B: /* JNP/JPO (jump parity odd) */
13441e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x7C: /* JLb/JNGEb (jump less) */
13442e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x7D: /* JGEb/JNLb (jump greater or equal) */
13443e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x7E: /* JLEb/JNGb (jump less or equal) */
13444e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x7F: /* JGb/JNLEb (jump greater) */
13445984d9b164dd17f07e603c41fe1e506e641e57d18sewardj    { Int    jmpDelta;
1344655085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* comment  = "";
13447984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      jmpDelta = (Int)getSDisp8(delta);
13448984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      vassert(-128 <= jmpDelta && jmpDelta < 128);
13449984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + jmpDelta;
13450e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      delta++;
13451984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      if (resteerCisOk
13452984d9b164dd17f07e603c41fe1e506e641e57d18sewardj          && vex_control.guest_chase_cond
134530d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj          && (Addr32)d32 != (Addr32)guest_EIP_bbstart
13454984d9b164dd17f07e603c41fe1e506e641e57d18sewardj          && jmpDelta < 0
13455beac530a718fcc646bc61fe60a86f599df54e1d7florian          && resteerOkFn( callback_opaque, (Addr32)d32) ) {
13456984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         /* Speculation: assume this backward branch is taken.  So we
13457984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            need to emit a side-exit to the insn following this one,
13458984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            on the negation of the condition, and continue at the
134590d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj            branch target address (d32).  If we wind up back at the
134600d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj            first instruction of the trace, just stop; it's better to
134610d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj            let the IR loop unroller handle that case. */
13462dbf550c3bb7d82eca7ea1436466dd51761fb7d4bsewardj         stmt( IRStmt_Exit(
13463dbf550c3bb7d82eca7ea1436466dd51761fb7d4bsewardj                  mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
13464dbf550c3bb7d82eca7ea1436466dd51761fb7d4bsewardj                  Ijk_Boring,
13465c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                  IRConst_U32(guest_EIP_bbstart+delta),
13466c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                  OFFB_EIP ) );
13467984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         dres.whatNext   = Dis_ResteerC;
134680eaa35ff5569f09129073be27c2f827926f7010dflorian         dres.continueAt = (Addr32)d32;
13469984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         comment = "(assumed taken)";
13470984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      }
13471984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      else
13472984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      if (resteerCisOk
13473984d9b164dd17f07e603c41fe1e506e641e57d18sewardj          && vex_control.guest_chase_cond
134740d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj          && (Addr32)d32 != (Addr32)guest_EIP_bbstart
13475984d9b164dd17f07e603c41fe1e506e641e57d18sewardj          && jmpDelta >= 0
13476984d9b164dd17f07e603c41fe1e506e641e57d18sewardj          && resteerOkFn( callback_opaque,
13477beac530a718fcc646bc61fe60a86f599df54e1d7florian                          (Addr32)(guest_EIP_bbstart+delta)) ) {
13478984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         /* Speculation: assume this forward branch is not taken.  So
13479984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            we need to emit a side-exit to d32 (the dest) and continue
13480984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            disassembling at the insn immediately following this
13481984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            one. */
13482984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         stmt( IRStmt_Exit(
13483984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                  mk_x86g_calculate_condition((X86Condcode)(opc - 0x70)),
13484984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                  Ijk_Boring,
13485c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                  IRConst_U32(d32),
13486c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                  OFFB_EIP ) );
13487984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         dres.whatNext   = Dis_ResteerC;
134880eaa35ff5569f09129073be27c2f827926f7010dflorian         dres.continueAt = guest_EIP_bbstart + delta;
13489984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         comment = "(assumed not taken)";
13490984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      }
13491984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      else {
13492984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         /* Conservative default translation - end the block at this
13493984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            point. */
13494c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jcc_01( &dres, (X86Condcode)(opc - 0x70),
13495984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                 (Addr32)(guest_EIP_bbstart+delta), d32);
13496c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
13497dbf550c3bb7d82eca7ea1436466dd51761fb7d4bsewardj      }
13498984d9b164dd17f07e603c41fe1e506e641e57d18sewardj      DIP("j%s-8 0x%x %s\n", name_X86Condcode(opc - 0x70), d32, comment);
13499e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      break;
13500984d9b164dd17f07e603c41fe1e506e641e57d18sewardj    }
13501e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
13502dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj   case 0xE3: /* JECXZ (for JCXZ see above) */
13503baa660847fc52547575169bcf2be772cd16364a6sewardj      if (sz != 4) goto decode_failure;
135049e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13505dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj      delta ++;
13506458a6f8809554fc459d90043e032f7c579620c97sewardj      stmt( IRStmt_Exit(
13507dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj               binop(Iop_CmpEQ32, getIReg(4,R_ECX), mkU32(0)),
13508893aadad7f29f7801ce26cb7575c16e90bd3767fsewardj            Ijk_Boring,
13509c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            IRConst_U32(d32),
13510c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            OFFB_EIP
13511dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj          ));
13512dc5d08457a168a463ca441179d2f7bc3eea2ebbesewardj      DIP("jecxz 0x%x\n", d32);
13513458a6f8809554fc459d90043e032f7c579620c97sewardj      break;
13514458a6f8809554fc459d90043e032f7c579620c97sewardj
13515baa660847fc52547575169bcf2be772cd16364a6sewardj   case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
13516baa660847fc52547575169bcf2be772cd16364a6sewardj   case 0xE1: /* LOOPE  disp8: decrement count, jump if count != 0 && ZF==1 */
13517baa660847fc52547575169bcf2be772cd16364a6sewardj   case 0xE2: /* LOOP   disp8: decrement count, jump if count != 0 */
13518baa660847fc52547575169bcf2be772cd16364a6sewardj    { /* Again, the docs say this uses ECX/CX as a count depending on
13519baa660847fc52547575169bcf2be772cd16364a6sewardj         the address size override, not the operand one.  Since we
13520baa660847fc52547575169bcf2be772cd16364a6sewardj         don't handle address size overrides, I guess that means
13521baa660847fc52547575169bcf2be772cd16364a6sewardj         ECX. */
13522baa660847fc52547575169bcf2be772cd16364a6sewardj      IRExpr* zbit  = NULL;
13523baa660847fc52547575169bcf2be772cd16364a6sewardj      IRExpr* count = NULL;
13524baa660847fc52547575169bcf2be772cd16364a6sewardj      IRExpr* cond  = NULL;
1352555085f8680acc89d727e321f3b34cae1a8c4093aflorian      const HChar* xtra = NULL;
13526baa660847fc52547575169bcf2be772cd16364a6sewardj
13527baa660847fc52547575169bcf2be772cd16364a6sewardj      if (sz != 4) goto decode_failure;
13528baa660847fc52547575169bcf2be772cd16364a6sewardj      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13529baa660847fc52547575169bcf2be772cd16364a6sewardj      delta++;
13530baa660847fc52547575169bcf2be772cd16364a6sewardj      putIReg(4, R_ECX, binop(Iop_Sub32, getIReg(4,R_ECX), mkU32(1)));
13531baa660847fc52547575169bcf2be772cd16364a6sewardj
13532baa660847fc52547575169bcf2be772cd16364a6sewardj      count = getIReg(4,R_ECX);
13533baa660847fc52547575169bcf2be772cd16364a6sewardj      cond = binop(Iop_CmpNE32, count, mkU32(0));
13534baa660847fc52547575169bcf2be772cd16364a6sewardj      switch (opc) {
13535baa660847fc52547575169bcf2be772cd16364a6sewardj         case 0xE2:
13536baa660847fc52547575169bcf2be772cd16364a6sewardj            xtra = "";
13537baa660847fc52547575169bcf2be772cd16364a6sewardj            break;
13538baa660847fc52547575169bcf2be772cd16364a6sewardj         case 0xE1:
13539baa660847fc52547575169bcf2be772cd16364a6sewardj            xtra = "e";
13540baa660847fc52547575169bcf2be772cd16364a6sewardj            zbit = mk_x86g_calculate_condition( X86CondZ );
13541baa660847fc52547575169bcf2be772cd16364a6sewardj	    cond = mkAnd1(cond, zbit);
13542baa660847fc52547575169bcf2be772cd16364a6sewardj            break;
13543baa660847fc52547575169bcf2be772cd16364a6sewardj         case 0xE0:
13544baa660847fc52547575169bcf2be772cd16364a6sewardj            xtra = "ne";
13545baa660847fc52547575169bcf2be772cd16364a6sewardj            zbit = mk_x86g_calculate_condition( X86CondNZ );
13546baa660847fc52547575169bcf2be772cd16364a6sewardj	    cond = mkAnd1(cond, zbit);
13547baa660847fc52547575169bcf2be772cd16364a6sewardj            break;
13548baa660847fc52547575169bcf2be772cd16364a6sewardj         default:
13549baa660847fc52547575169bcf2be772cd16364a6sewardj	    vassert(0);
13550baa660847fc52547575169bcf2be772cd16364a6sewardj      }
13551c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U32(d32), OFFB_EIP) );
13552baa660847fc52547575169bcf2be772cd16364a6sewardj
13553baa660847fc52547575169bcf2be772cd16364a6sewardj      DIP("loop%s 0x%x\n", xtra, d32);
13554baa660847fc52547575169bcf2be772cd16364a6sewardj      break;
13555baa660847fc52547575169bcf2be772cd16364a6sewardj    }
135561813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
135571813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   /* ------------------------ IMUL ----------------------- */
135581813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
135591813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   case 0x69: /* IMUL Iv, Ev, Gv */
135601813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
135611813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      break;
135621813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   case 0x6B: /* IMUL Ib, Ev, Gv */
135631813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
135641813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      break;
135650611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
135660611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   /* ------------------------ MOV ------------------------ */
135670611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
135680611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x88: /* MOV Gb,Eb */
135690611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      delta = dis_mov_G_E(sorb, 1, delta);
135700611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
13571c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
13572c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   case 0x89: /* MOV Gv,Ev */
13573c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      delta = dis_mov_G_E(sorb, sz, delta);
13574c9a6570e86f4252f8a486b4df48de8710d357a4asewardj      break;
13575c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
13576c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0x8A: /* MOV Eb,Gb */
13577c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      delta = dis_mov_E_G(sorb, 1, delta);
13578c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
13579e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
13580e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   case 0x8B: /* MOV Ev,Gv */
13581e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      delta = dis_mov_E_G(sorb, sz, delta);
13582e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
13583e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
13584e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x8D: /* LEA M,Gv */
13585e9460bd464d943658e8a2ac4489fb2baa0e16682sewardj      if (sz != 4)
13586e9460bd464d943658e8a2ac4489fb2baa0e16682sewardj         goto decode_failure;
13587e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      modrm = getIByte(delta);
13588e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      if (epartIsReg(modrm))
13589e9460bd464d943658e8a2ac4489fb2baa0e16682sewardj         goto decode_failure;
13590e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      /* NOTE!  this is the one place where a segment override prefix
13591e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj         has no effect on the address calculation.  Therefore we pass
13592e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj         zero instead of sorb here. */
13593e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
13594e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      delta += alen;
13595940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      putIReg(sz, gregOfRM(modrm), mkexpr(addr));
13596e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
13597e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj                            nameIReg(sz,gregOfRM(modrm)));
13598e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
13599e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
13600063f02f7e77ca024d24786bec402ca296a05bd6esewardj   case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
13601063f02f7e77ca024d24786bec402ca296a05bd6esewardj      delta = dis_mov_Sw_Ew(sorb, sz, delta);
13602063f02f7e77ca024d24786bec402ca296a05bd6esewardj      break;
13603063f02f7e77ca024d24786bec402ca296a05bd6esewardj
136047df596b1e36840e2d74c90aa55589934add61ccfsewardj   case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
136057df596b1e36840e2d74c90aa55589934add61ccfsewardj      delta = dis_mov_Ew_Sw(sorb, delta);
136067df596b1e36840e2d74c90aa55589934add61ccfsewardj      break;
136077df596b1e36840e2d74c90aa55589934add61ccfsewardj
136084385281d538e7052cc6dc45998bdecd4672c4036sewardj   case 0xA0: /* MOV Ob,AL */
136094385281d538e7052cc6dc45998bdecd4672c4036sewardj      sz = 1;
136104385281d538e7052cc6dc45998bdecd4672c4036sewardj      /* Fall through ... */
136110c12ea83187de020a5484b4327e2427ea3451380sewardj   case 0xA1: /* MOV Ov,eAX */
136120c12ea83187de020a5484b4327e2427ea3451380sewardj      d32 = getUDisp32(delta); delta += 4;
136130c12ea83187de020a5484b4327e2427ea3451380sewardj      ty = szToITy(sz);
136140c12ea83187de020a5484b4327e2427ea3451380sewardj      addr = newTemp(Ity_I32);
136150c12ea83187de020a5484b4327e2427ea3451380sewardj      assign( addr, handleSegOverride(sorb, mkU32(d32)) );
136160c12ea83187de020a5484b4327e2427ea3451380sewardj      putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
136170c12ea83187de020a5484b4327e2427ea3451380sewardj      DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
136180c12ea83187de020a5484b4327e2427ea3451380sewardj                                d32, nameIReg(sz,R_EAX));
136190c12ea83187de020a5484b4327e2427ea3451380sewardj      break;
136200c12ea83187de020a5484b4327e2427ea3451380sewardj
13621180e8b39d5b4271e64634162986749c43536647csewardj   case 0xA2: /* MOV Ob,AL */
13622180e8b39d5b4271e64634162986749c43536647csewardj      sz = 1;
13623180e8b39d5b4271e64634162986749c43536647csewardj      /* Fall through ... */
13624750f407b6be1aac303964a219acf0a6de8b8c4dasewardj   case 0xA3: /* MOV eAX,Ov */
13625750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      d32 = getUDisp32(delta); delta += 4;
13626750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      ty = szToITy(sz);
13627750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      addr = newTemp(Ity_I32);
13628750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13629750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
13630750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
13631750f407b6be1aac303964a219acf0a6de8b8c4dasewardj                                sorbTxt(sorb), d32);
13632750f407b6be1aac303964a219acf0a6de8b8c4dasewardj      break;
13633e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
13634c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB0: /* MOV imm,AL */
13635c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB1: /* MOV imm,CL */
13636c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB2: /* MOV imm,DL */
13637c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB3: /* MOV imm,BL */
13638c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB4: /* MOV imm,AH */
13639c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB5: /* MOV imm,CH */
13640c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB6: /* MOV imm,DH */
13641c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xB7: /* MOV imm,BH */
13642c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      d32 = getIByte(delta); delta += 1;
13643c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      putIReg(1, opc-0xB0, mkU8(d32));
13644c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
13645c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
136467ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj
13647e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xB8: /* MOV imm,eAX */
13648e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xB9: /* MOV imm,eCX */
13649e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xBA: /* MOV imm,eDX */
13650e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xBB: /* MOV imm,eBX */
13651e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xBC: /* MOV imm,eSP */
13652e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xBD: /* MOV imm,eBP */
13653e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xBE: /* MOV imm,eSI */
13654e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0xBF: /* MOV imm,eDI */
13655e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      d32 = getUDisp(sz,delta); delta += sz;
13656e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
13657e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
13658e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      break;
13659e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
136601bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj   case 0xC6: /* C6 /0 = MOV Ib,Eb */
1366177b86be374085943e902075b305ff047a053aac6sewardj      sz = 1;
136621bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj      goto maybe_do_Mov_I_E;
136631bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj   case 0xC7: /* C7 /0 = MOV Iv,Ev */
136641bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj      goto maybe_do_Mov_I_E;
13665e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
136661bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj   maybe_do_Mov_I_E:
13667e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      modrm = getIByte(delta);
136681bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj      if (gregOfRM(modrm) == 0) {
136691bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj         if (epartIsReg(modrm)) {
136701bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            delta++; /* mod/rm byte */
136711bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            d32 = getUDisp(sz,delta); delta += sz;
136721bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
136731bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
136741bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj                                     nameIReg(sz,eregOfRM(modrm)));
136751bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj         } else {
136761bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            addr = disAMode ( &alen, sorb, delta, dis_buf );
136771bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            delta += alen;
136781bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            d32 = getUDisp(sz,delta); delta += sz;
136791bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
136801bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj            DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
136811bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj         }
136821bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj         break;
13683e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      }
136841bf44e3f8f4e4e88461d3debeb263c5a5654f6d8sewardj      goto decode_failure;
13685e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
136861813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   /* ------------------------ opl imm, A ----------------- */
136871813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
136881813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   case 0x04: /* ADD Ib, AL */
13689a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_Add8, True, delta, "add" );
136901813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      break;
1369177b86be374085943e902075b305ff047a053aac6sewardj   case 0x05: /* ADD Iv, eAX */
13692a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_Add8, True, delta, "add" );
1369377b86be374085943e902075b305ff047a053aac6sewardj      break;
1369477b86be374085943e902075b305ff047a053aac6sewardj
13695940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   case 0x0C: /* OR Ib, AL */
13696a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_Or8, True, delta, "or" );
13697940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
136988229288c4fb1331c1e638bacdd55566e1caad9edsewardj   case 0x0D: /* OR Iv, eAX */
13699a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
137008229288c4fb1331c1e638bacdd55566e1caad9edsewardj      break;
137018229288c4fb1331c1e638bacdd55566e1caad9edsewardj
13702eca203688d1c4f2d4c3327ebf0f4124e098492e8sewardj   case 0x14: /* ADC Ib, AL */
13703eca203688d1c4f2d4c3327ebf0f4124e098492e8sewardj      delta = dis_op_imm_A(  1, True, Iop_Add8, True, delta, "adc" );
13704eca203688d1c4f2d4c3327ebf0f4124e098492e8sewardj      break;
13705a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj   case 0x15: /* ADC Iv, eAX */
13706eca203688d1c4f2d4c3327ebf0f4124e098492e8sewardj      delta = dis_op_imm_A( sz, True, Iop_Add8, True, delta, "adc" );
13707a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      break;
13708a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj
137092fbae083dad486e8e623011b4dd68ba204c2a228sewardj   case 0x1C: /* SBB Ib, AL */
137102fbae083dad486e8e623011b4dd68ba204c2a228sewardj      delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
137112fbae083dad486e8e623011b4dd68ba204c2a228sewardj      break;
137122fbae083dad486e8e623011b4dd68ba204c2a228sewardj   case 0x1D: /* SBB Iv, eAX */
137132fbae083dad486e8e623011b4dd68ba204c2a228sewardj      delta = dis_op_imm_A( sz, True, Iop_Sub8, True, delta, "sbb" );
137142fbae083dad486e8e623011b4dd68ba204c2a228sewardj      break;
137152fbae083dad486e8e623011b4dd68ba204c2a228sewardj
13716940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   case 0x24: /* AND Ib, AL */
13717a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_And8, True, delta, "and" );
13718940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
13719c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0x25: /* AND Iv, eAX */
13720a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
13721c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
137220611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
137230611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x2C: /* SUB Ib, AL */
13724a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_Sub8, True, delta, "sub" );
137250611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
1372668511549b138ef55c8d31088cb0f20a72d83ab2bsewardj   case 0x2D: /* SUB Iv, eAX */
13727a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
1372868511549b138ef55c8d31088cb0f20a72d83ab2bsewardj      break;
1372968511549b138ef55c8d31088cb0f20a72d83ab2bsewardj
137301c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   case 0x34: /* XOR Ib, AL */
13731a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_Xor8, True, delta, "xor" );
137321c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      break;
13733caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   case 0x35: /* XOR Iv, eAX */
13734a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
13735caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      break;
13736caca9d0d3729c36af6ae02b0654cb289101248cbsewardj
137370611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x3C: /* CMP Ib, AL */
13738a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_Sub8, False, delta, "cmp" );
137390611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
137400611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x3D: /* CMP Iv, eAX */
13741a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
137420611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
137430611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
1374477b86be374085943e902075b305ff047a053aac6sewardj   case 0xA8: /* TEST Ib, AL */
13745a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A(  1, False, Iop_And8, False, delta, "test" );
1374677b86be374085943e902075b305ff047a053aac6sewardj      break;
13747c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0xA9: /* TEST Iv, eAX */
13748a718d5dd218b5369fa738395b22d1dca1dcfb900sewardj      delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
13749c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
13750c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
137511c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   /* ------------------------ opl Ev, Gv ----------------- */
137521c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
1375389cd09353a584000edaaa61558b27253bdea7452sewardj   case 0x02: /* ADD Eb,Gb */
1375489cd09353a584000edaaa61558b27253bdea7452sewardj      delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
1375589cd09353a584000edaaa61558b27253bdea7452sewardj      break;
137569334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x03: /* ADD Ev,Gv */
13757180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
137589334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      break;
137599334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
137607ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj   case 0x0A: /* OR Eb,Gb */
13761180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
137627ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      break;
13763c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0x0B: /* OR Ev,Gv */
13764180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
13765c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
137662fbae083dad486e8e623011b4dd68ba204c2a228sewardj
137672fbae083dad486e8e623011b4dd68ba204c2a228sewardj   case 0x12: /* ADC Eb,Gb */
137682fbae083dad486e8e623011b4dd68ba204c2a228sewardj      delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
137692fbae083dad486e8e623011b4dd68ba204c2a228sewardj      break;
13770c4eaff3aa358fc5c73b534c7e78366555184244fsewardj   case 0x13: /* ADC Ev,Gv */
13771c4eaff3aa358fc5c73b534c7e78366555184244fsewardj      delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
13772c4eaff3aa358fc5c73b534c7e78366555184244fsewardj      break;
13773c4eaff3aa358fc5c73b534c7e78366555184244fsewardj
137742fbae083dad486e8e623011b4dd68ba204c2a228sewardj   case 0x1A: /* SBB Eb,Gb */
137752fbae083dad486e8e623011b4dd68ba204c2a228sewardj      delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
137762fbae083dad486e8e623011b4dd68ba204c2a228sewardj      break;
13777180e8b39d5b4271e64634162986749c43536647csewardj   case 0x1B: /* SBB Ev,Gv */
13778180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
13779180e8b39d5b4271e64634162986749c43536647csewardj      break;
13780180e8b39d5b4271e64634162986749c43536647csewardj
137811c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj   case 0x22: /* AND Eb,Gb */
137821c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
137831c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      break;
13784940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   case 0x23: /* AND Ev,Gv */
13785180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
13786940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
13787940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
13788180e8b39d5b4271e64634162986749c43536647csewardj   case 0x2A: /* SUB Eb,Gb */
13789180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
13790180e8b39d5b4271e64634162986749c43536647csewardj      break;
137910611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x2B: /* SUB Ev,Gv */
13792180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
137930611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
13794c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
13795c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0x32: /* XOR Eb,Gb */
13796180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
13797c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
137981813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   case 0x33: /* XOR Ev,Gv */
13799180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
138001813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      break;
138011813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
13802c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0x3A: /* CMP Eb,Gb */
13803180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
13804c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
13805e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   case 0x3B: /* CMP Ev,Gv */
13806180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
13807e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      break;
13808e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
138090611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x84: /* TEST Eb,Gb */
13810180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
138110611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
13812e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   case 0x85: /* TEST Ev,Gv */
13813180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
13814e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
13815e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
13816180e8b39d5b4271e64634162986749c43536647csewardj   /* ------------------------ opl Gv, Ev ----------------- */
13817180e8b39d5b4271e64634162986749c43536647csewardj
13818180e8b39d5b4271e64634162986749c43536647csewardj   case 0x00: /* ADD Gb,Eb */
13819e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13820e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Add8, True, 1, delta, "add" );
13821180e8b39d5b4271e64634162986749c43536647csewardj      break;
13822e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   case 0x01: /* ADD Gv,Ev */
13823e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13824e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Add8, True, sz, delta, "add" );
13825e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
13826e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
13827940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   case 0x08: /* OR Gb,Eb */
13828e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13829e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Or8, True, 1, delta, "or" );
13830940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
138319334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x09: /* OR Gv,Ev */
13832e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13833e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Or8, True, sz, delta, "or" );
138349334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      break;
138359334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
13836a238471814bd386aeb58a76718b41e68b1a794b2sewardj   case 0x10: /* ADC Gb,Eb */
13837e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13838e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Add8, True, 1, delta, "adc" );
13839a238471814bd386aeb58a76718b41e68b1a794b2sewardj      break;
13840caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   case 0x11: /* ADC Gv,Ev */
13841e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13842e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Add8, True, sz, delta, "adc" );
13843caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      break;
13844caca9d0d3729c36af6ae02b0654cb289101248cbsewardj
13845a238471814bd386aeb58a76718b41e68b1a794b2sewardj   case 0x18: /* SBB Gb,Eb */
13846e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13847e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Sub8, True, 1, delta, "sbb" );
13848a238471814bd386aeb58a76718b41e68b1a794b2sewardj      break;
13849caca9d0d3729c36af6ae02b0654cb289101248cbsewardj   case 0x19: /* SBB Gv,Ev */
13850e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, True,
13851e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Sub8, True, sz, delta, "sbb" );
13852caca9d0d3729c36af6ae02b0654cb289101248cbsewardj      break;
13853caca9d0d3729c36af6ae02b0654cb289101248cbsewardj
13854a238471814bd386aeb58a76718b41e68b1a794b2sewardj   case 0x20: /* AND Gb,Eb */
13855e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13856e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_And8, True, 1, delta, "and" );
13857a238471814bd386aeb58a76718b41e68b1a794b2sewardj      break;
138580611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x21: /* AND Gv,Ev */
13859e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13860e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_And8, True, sz, delta, "and" );
138610611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
138620611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
13863180e8b39d5b4271e64634162986749c43536647csewardj   case 0x28: /* SUB Gb,Eb */
13864e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13865e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Sub8, True, 1, delta, "sub" );
13866180e8b39d5b4271e64634162986749c43536647csewardj      break;
13867e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   case 0x29: /* SUB Gv,Ev */
13868e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13869e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Sub8, True, sz, delta, "sub" );
13870e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
13871e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
13872c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   case 0x30: /* XOR Gb,Eb */
13873e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13874e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Xor8, True, 1, delta, "xor" );
13875c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
13876e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x31: /* XOR Gv,Ev */
13877e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13878e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Xor8, True, sz, delta, "xor" );
13879e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      break;
13880e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
138810611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x38: /* CMP Gb,Eb */
13882e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13883e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Sub8, False, 1, delta, "cmp" );
138840611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
13885e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj   case 0x39: /* CMP Gv,Ev */
13886e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_op2_G_E ( sorb, pfx_lock, False,
13887e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                            Iop_Sub8, False, sz, delta, "cmp" );
13888e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      break;
13889e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj
138909334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   /* ------------------------ POP ------------------------ */
138919334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
138929334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x58: /* POP eAX */
138939334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x59: /* POP eCX */
138949334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x5A: /* POP eDX */
138959334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x5B: /* POP eBX */
138969334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x5D: /* POP eBP */
138979334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x5E: /* POP eSI */
138989334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x5F: /* POP eDI */
138999334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj   case 0x5C: /* POP eSP */
139009334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      vassert(sz == 2 || sz == 4);
139019334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
139029334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      assign(t2, getIReg(4, R_ESP));
139039334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
139049334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
139059334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      putIReg(sz, opc-0x58, mkexpr(t1));
139069334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
139079334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      break;
139089334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
13909a238471814bd386aeb58a76718b41e68b1a794b2sewardj   case 0x9D: /* POPF */
13910a238471814bd386aeb58a76718b41e68b1a794b2sewardj      vassert(sz == 2 || sz == 4);
13911a238471814bd386aeb58a76718b41e68b1a794b2sewardj      t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13912a238471814bd386aeb58a76718b41e68b1a794b2sewardj      assign(t2, getIReg(4, R_ESP));
13913c22a6fd7322935b2480a4f5924cbfda65731cb2bsewardj      assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
13914a238471814bd386aeb58a76718b41e68b1a794b2sewardj      putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
13915a238471814bd386aeb58a76718b41e68b1a794b2sewardj
139160e9a0f551e190b475150dcd6bc4500033eb05338sewardj      /* Generate IR to set %EFLAGS{O,S,Z,A,C,P,D,ID,AC} from the
139170e9a0f551e190b475150dcd6bc4500033eb05338sewardj	 value in t1. */
139180e9a0f551e190b475150dcd6bc4500033eb05338sewardj      set_EFLAGS_from_value( t1, True/*emit_AC_emwarn*/,
139190e9a0f551e190b475150dcd6bc4500033eb05338sewardj                                 ((Addr32)guest_EIP_bbstart)+delta );
139206d26984a0df6a7d20b658bac6edf869eb872cca3sewardj
13921a238471814bd386aeb58a76718b41e68b1a794b2sewardj      DIP("popf%c\n", nameISize(sz));
13922a238471814bd386aeb58a76718b41e68b1a794b2sewardj      break;
13923a238471814bd386aeb58a76718b41e68b1a794b2sewardj
13924bbdc6225e71309bd47b639aba9c799a0496c457esewardj   case 0x61: /* POPA */
13925bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* This is almost certainly wrong for sz==2.  So ... */
13926bbdc6225e71309bd47b639aba9c799a0496c457esewardj      if (sz != 4) goto decode_failure;
13927bbdc6225e71309bd47b639aba9c799a0496c457esewardj
13928bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* t5 is the old %ESP value. */
13929bbdc6225e71309bd47b639aba9c799a0496c457esewardj      t5 = newTemp(Ity_I32);
13930bbdc6225e71309bd47b639aba9c799a0496c457esewardj      assign( t5, getIReg(4, R_ESP) );
13931bbdc6225e71309bd47b639aba9c799a0496c457esewardj
13932bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* Reload all the registers, except %esp. */
13933bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
13934bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
13935bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
13936bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
13937bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* ignore saved %ESP */
13938bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
13939bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
13940bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
13941bbdc6225e71309bd47b639aba9c799a0496c457esewardj
13942bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* and move %ESP back up */
13943bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
13944bbdc6225e71309bd47b639aba9c799a0496c457esewardj
13945a3d1a66a58870e3afed8a9fe08336f859f6af3ebsewardj      DIP("popa%c\n", nameISize(sz));
13946bbdc6225e71309bd47b639aba9c799a0496c457esewardj      break;
13947feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
13948feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj   case 0x8F: /* POPL/POPW m32 */
13949fcff178bf2302f24b54957339082339a44ab5e71sewardj     { Int    len;
13950fcff178bf2302f24b54957339082339a44ab5e71sewardj       UChar  rm = getIByte(delta);
13951feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
13952feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       /* make sure this instruction is correct POP */
13953fcff178bf2302f24b54957339082339a44ab5e71sewardj       if (epartIsReg(rm) || gregOfRM(rm) != 0)
13954fcff178bf2302f24b54957339082339a44ab5e71sewardj          goto decode_failure;
13955feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       /* and has correct size */
13956fcff178bf2302f24b54957339082339a44ab5e71sewardj       if (sz != 4 && sz != 2)
13957fcff178bf2302f24b54957339082339a44ab5e71sewardj          goto decode_failure;
13958fcff178bf2302f24b54957339082339a44ab5e71sewardj       ty = szToITy(sz);
13959fcff178bf2302f24b54957339082339a44ab5e71sewardj
13960fcff178bf2302f24b54957339082339a44ab5e71sewardj       t1 = newTemp(Ity_I32); /* stack address */
13961fcff178bf2302f24b54957339082339a44ab5e71sewardj       t3 = newTemp(ty); /* data */
13962feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       /* set t1 to ESP: t1 = ESP */
13963feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       assign( t1, getIReg(4, R_ESP) );
13964feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       /* load M[ESP] to virtual register t3: t3 = M[t1] */
13965fcff178bf2302f24b54957339082339a44ab5e71sewardj       assign( t3, loadLE(ty, mkexpr(t1)) );
13966feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
13967feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       /* increase ESP; must be done before the STORE.  Intel manual says:
13968feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            If the ESP register is used as a base register for addressing
13969feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            a destination operand in memory, the POP instruction computes
13970feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            the effective address of the operand after it increments the
13971feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj            ESP register.
13972feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       */
13973feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
13974feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
13975feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       /* resolve MODR/M */
13976feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       addr = disAMode ( &len, sorb, delta, dis_buf);
13977feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       storeLE( mkexpr(addr), mkexpr(t3) );
13978feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
13979fcff178bf2302f24b54957339082339a44ab5e71sewardj       DIP("pop%c %s\n", sz==2 ? 'w' : 'l', dis_buf);
13980feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
13981feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       delta += len;
13982feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj       break;
13983feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj     }
13984feeb8a88880bb85dd5f7d5a3788de9e458ea43e5sewardj
139855c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x1F: /* POP %DS */
139865c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_pop_segreg( R_DS, sz ); break;
139875c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x07: /* POP %ES */
139885c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_pop_segreg( R_ES, sz ); break;
139895c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x17: /* POP %SS */
139905c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_pop_segreg( R_SS, sz ); break;
13991d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
13992d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   /* ------------------------ PUSH ----------------------- */
13993d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
13994d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x50: /* PUSH eAX */
13995d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x51: /* PUSH eCX */
13996d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x52: /* PUSH eDX */
13997d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x53: /* PUSH eBX */
13998d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x55: /* PUSH eBP */
13999d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x56: /* PUSH eSI */
14000d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x57: /* PUSH eDI */
14001d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x54: /* PUSH eSP */
14002d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      /* This is the Right Way, in that the value to be pushed is
14003d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         established before %esp is changed, so that pushl %esp
14004d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj         correctly pushes the old value. */
14005d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      vassert(sz == 2 || sz == 4);
14006d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      ty = sz==2 ? Ity_I16 : Ity_I32;
14007883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      t1 = newTemp(ty); t2 = newTemp(Ity_I32);
1400841f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      assign(t1, getIReg(sz, opc-0x50));
1400941f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
1401041f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      putIReg(4, R_ESP, mkexpr(t2) );
1401141f43bcdee3e150a74a2e8c8e3b5bc5f5fda3215sewardj      storeLE(mkexpr(t2),mkexpr(t1));
14012d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
14013d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      break;
14014d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14015d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
140160c12ea83187de020a5484b4327e2427ea3451380sewardj   case 0x68: /* PUSH Iv */
140170c12ea83187de020a5484b4327e2427ea3451380sewardj      d32 = getUDisp(sz,delta); delta += sz;
140180c12ea83187de020a5484b4327e2427ea3451380sewardj      goto do_push_I;
14019741153c4301023a420ab45b8a10b8e1bac968822sewardj   case 0x6A: /* PUSH Ib, sign-extended to sz */
14020741153c4301023a420ab45b8a10b8e1bac968822sewardj      d32 = getSDisp8(delta); delta += 1;
14021741153c4301023a420ab45b8a10b8e1bac968822sewardj      goto do_push_I;
140220c12ea83187de020a5484b4327e2427ea3451380sewardj   do_push_I:
140230c12ea83187de020a5484b4327e2427ea3451380sewardj      ty = szToITy(sz);
140240c12ea83187de020a5484b4327e2427ea3451380sewardj      t1 = newTemp(Ity_I32); t2 = newTemp(ty);
140250c12ea83187de020a5484b4327e2427ea3451380sewardj      assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
140260c12ea83187de020a5484b4327e2427ea3451380sewardj      putIReg(4, R_ESP, mkexpr(t1) );
14027c4255a0df097f3d6740ec768fa145bca6921961bsewardj      /* stop mkU16 asserting if d32 is a negative 16-bit number
14028c4255a0df097f3d6740ec768fa145bca6921961bsewardj         (bug #132813) */
14029c4255a0df097f3d6740ec768fa145bca6921961bsewardj      if (ty == Ity_I16)
14030c4255a0df097f3d6740ec768fa145bca6921961bsewardj         d32 &= 0xFFFF;
140310c12ea83187de020a5484b4327e2427ea3451380sewardj      storeLE( mkexpr(t1), mkU(ty,d32) );
140320c12ea83187de020a5484b4327e2427ea3451380sewardj      DIP("push%c $0x%x\n", nameISize(sz), d32);
140330c12ea83187de020a5484b4327e2427ea3451380sewardj      break;
140340c12ea83187de020a5484b4327e2427ea3451380sewardj
14035a238471814bd386aeb58a76718b41e68b1a794b2sewardj   case 0x9C: /* PUSHF */ {
14036a238471814bd386aeb58a76718b41e68b1a794b2sewardj      vassert(sz == 2 || sz == 4);
14037a238471814bd386aeb58a76718b41e68b1a794b2sewardj
14038a238471814bd386aeb58a76718b41e68b1a794b2sewardj      t1 = newTemp(Ity_I32);
14039a238471814bd386aeb58a76718b41e68b1a794b2sewardj      assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
14040a238471814bd386aeb58a76718b41e68b1a794b2sewardj      putIReg(4, R_ESP, mkexpr(t1) );
14041a238471814bd386aeb58a76718b41e68b1a794b2sewardj
14042bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      /* Calculate OSZACP, and patch in fixed fields as per
14043bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         Intel docs.
14044bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         - bit 1 is always 1
14045bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         - bit 9 is Interrupt Enable (should always be 1 in user mode?)
14046bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      */
14047a238471814bd386aeb58a76718b41e68b1a794b2sewardj      t2 = newTemp(Ity_I32);
14048bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      assign( t2, binop(Iop_Or32,
14049bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj                        mk_x86g_calculate_eflags_all(),
14050bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj                        mkU32( (1<<1)|(1<<9) ) ));
14051a238471814bd386aeb58a76718b41e68b1a794b2sewardj
14052f9c74fef6758ac5e46c32a3e896d92343e34c049sewardj      /* Patch in the D flag.  This can simply be a copy of bit 10 of
14053f9c74fef6758ac5e46c32a3e896d92343e34c049sewardj         baseBlock[OFFB_DFLAG]. */
14054a238471814bd386aeb58a76718b41e68b1a794b2sewardj      t3 = newTemp(Ity_I32);
14055a238471814bd386aeb58a76718b41e68b1a794b2sewardj      assign( t3, binop(Iop_Or32,
14056a238471814bd386aeb58a76718b41e68b1a794b2sewardj                        mkexpr(t2),
14057a238471814bd386aeb58a76718b41e68b1a794b2sewardj                        binop(Iop_And32,
14058f9c74fef6758ac5e46c32a3e896d92343e34c049sewardj                              IRExpr_Get(OFFB_DFLAG,Ity_I32),
140595bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                              mkU32(1<<10)))
14060a238471814bd386aeb58a76718b41e68b1a794b2sewardj            );
14061006a6a2f15f48f705895a516d4883e8f8142e910sewardj
14062006a6a2f15f48f705895a516d4883e8f8142e910sewardj      /* And patch in the ID flag. */
14063006a6a2f15f48f705895a516d4883e8f8142e910sewardj      t4 = newTemp(Ity_I32);
14064006a6a2f15f48f705895a516d4883e8f8142e910sewardj      assign( t4, binop(Iop_Or32,
14065006a6a2f15f48f705895a516d4883e8f8142e910sewardj                        mkexpr(t3),
14066006a6a2f15f48f705895a516d4883e8f8142e910sewardj                        binop(Iop_And32,
140675bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                              binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
14068006a6a2f15f48f705895a516d4883e8f8142e910sewardj                                               mkU8(21)),
140695bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj                              mkU32(1<<21)))
14070006a6a2f15f48f705895a516d4883e8f8142e910sewardj            );
14071006a6a2f15f48f705895a516d4883e8f8142e910sewardj
140726d26984a0df6a7d20b658bac6edf869eb872cca3sewardj      /* And patch in the AC flag. */
140736d26984a0df6a7d20b658bac6edf869eb872cca3sewardj      t5 = newTemp(Ity_I32);
140746d26984a0df6a7d20b658bac6edf869eb872cca3sewardj      assign( t5, binop(Iop_Or32,
140756d26984a0df6a7d20b658bac6edf869eb872cca3sewardj                        mkexpr(t4),
140766d26984a0df6a7d20b658bac6edf869eb872cca3sewardj                        binop(Iop_And32,
140776d26984a0df6a7d20b658bac6edf869eb872cca3sewardj                              binop(Iop_Shl32, IRExpr_Get(OFFB_ACFLAG,Ity_I32),
140786d26984a0df6a7d20b658bac6edf869eb872cca3sewardj                                               mkU8(18)),
140796d26984a0df6a7d20b658bac6edf869eb872cca3sewardj                              mkU32(1<<18)))
140806d26984a0df6a7d20b658bac6edf869eb872cca3sewardj            );
140816d26984a0df6a7d20b658bac6edf869eb872cca3sewardj
14082a238471814bd386aeb58a76718b41e68b1a794b2sewardj      /* if sz==2, the stored value needs to be narrowed. */
14083a238471814bd386aeb58a76718b41e68b1a794b2sewardj      if (sz == 2)
140846d26984a0df6a7d20b658bac6edf869eb872cca3sewardj        storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t5)) );
14085a238471814bd386aeb58a76718b41e68b1a794b2sewardj      else
140866d26984a0df6a7d20b658bac6edf869eb872cca3sewardj        storeLE( mkexpr(t1), mkexpr(t5) );
14087a238471814bd386aeb58a76718b41e68b1a794b2sewardj
14088a238471814bd386aeb58a76718b41e68b1a794b2sewardj      DIP("pushf%c\n", nameISize(sz));
14089a238471814bd386aeb58a76718b41e68b1a794b2sewardj      break;
14090a238471814bd386aeb58a76718b41e68b1a794b2sewardj   }
14091a238471814bd386aeb58a76718b41e68b1a794b2sewardj
14092bbdc6225e71309bd47b639aba9c799a0496c457esewardj   case 0x60: /* PUSHA */
14093bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* This is almost certainly wrong for sz==2.  So ... */
14094bbdc6225e71309bd47b639aba9c799a0496c457esewardj      if (sz != 4) goto decode_failure;
14095bbdc6225e71309bd47b639aba9c799a0496c457esewardj
14096bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* This is the Right Way, in that the value to be pushed is
14097bbdc6225e71309bd47b639aba9c799a0496c457esewardj         established before %esp is changed, so that pusha
14098bbdc6225e71309bd47b639aba9c799a0496c457esewardj         correctly pushes the old %esp value.  New value of %esp is
14099bbdc6225e71309bd47b639aba9c799a0496c457esewardj         pushed at start. */
14100bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* t0 is the %ESP value we're going to push. */
14101bbdc6225e71309bd47b639aba9c799a0496c457esewardj      t0 = newTemp(Ity_I32);
14102bbdc6225e71309bd47b639aba9c799a0496c457esewardj      assign( t0, getIReg(4, R_ESP) );
14103bbdc6225e71309bd47b639aba9c799a0496c457esewardj
14104bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* t5 will be the new %ESP value. */
14105bbdc6225e71309bd47b639aba9c799a0496c457esewardj      t5 = newTemp(Ity_I32);
14106bbdc6225e71309bd47b639aba9c799a0496c457esewardj      assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
14107bbdc6225e71309bd47b639aba9c799a0496c457esewardj
14108bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* Update guest state before prodding memory. */
14109bbdc6225e71309bd47b639aba9c799a0496c457esewardj      putIReg(4, R_ESP, mkexpr(t5));
14110bbdc6225e71309bd47b639aba9c799a0496c457esewardj
14111bbdc6225e71309bd47b639aba9c799a0496c457esewardj      /* Dump all the registers. */
14112bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
14113bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
14114bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
14115bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
14116bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
14117bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
14118bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
14119bbdc6225e71309bd47b639aba9c799a0496c457esewardj      storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
14120bbdc6225e71309bd47b639aba9c799a0496c457esewardj
14121bbdc6225e71309bd47b639aba9c799a0496c457esewardj      DIP("pusha%c\n", nameISize(sz));
14122bbdc6225e71309bd47b639aba9c799a0496c457esewardj      break;
14123bbdc6225e71309bd47b639aba9c799a0496c457esewardj
141245c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x0E: /* PUSH %CS */
141255c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_push_segreg( R_CS, sz ); break;
141265c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x1E: /* PUSH %DS */
141275c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_push_segreg( R_DS, sz ); break;
141285c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x06: /* PUSH %ES */
141295c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_push_segreg( R_ES, sz ); break;
141305c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj   case 0x16: /* PUSH %SS */
141315c5f72cb7314c13680fe6834bc26d8b3ba9d0cf7sewardj      dis_push_segreg( R_SS, sz ); break;
14132458a6f8809554fc459d90043e032f7c579620c97sewardj
14133458a6f8809554fc459d90043e032f7c579620c97sewardj   /* ------------------------ SCAS et al ----------------- */
14134458a6f8809554fc459d90043e032f7c579620c97sewardj
14135458a6f8809554fc459d90043e032f7c579620c97sewardj   case 0xA4: /* MOVS, no REP prefix */
14136458a6f8809554fc459d90043e032f7c579620c97sewardj   case 0xA5:
141379c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      if (sorb != 0)
141389c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj         goto decode_failure; /* else dis_string_op asserts */
14139458a6f8809554fc459d90043e032f7c579620c97sewardj      dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
14140458a6f8809554fc459d90043e032f7c579620c97sewardj      break;
14141458a6f8809554fc459d90043e032f7c579620c97sewardj
141428d4d223b7a4c77d4b8bb3e2c59ff87369e2b0127sewardj  case 0xA6: /* CMPSb, no REP prefix */
1414333b53540401e9796039e647b6e91248b8b944b0esewardj  case 0xA7:
141449c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      if (sorb != 0)
141459c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj         goto decode_failure; /* else dis_string_op asserts */
141469c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
141479c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      break;
1414833b53540401e9796039e647b6e91248b8b944b0esewardj
14149883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj   case 0xAA: /* STOS, no REP prefix */
1415047341042b1b4140b5b4b42983df7bec015f7beecsewardj   case 0xAB:
141519c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      if (sorb != 0)
141529c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj         goto decode_failure; /* else dis_string_op asserts */
14153883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
14154883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj      break;
1415533b53540401e9796039e647b6e91248b8b944b0esewardj
1415610ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   case 0xAC: /* LODS, no REP prefix */
1415710ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj   case 0xAD:
141589c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      if (sorb != 0)
141599c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj         goto decode_failure; /* else dis_string_op asserts */
1416010ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj      dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
1416110ca4eb0751a48347cb6f539aff8b015a4eb94fasewardj      break;
141622d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj
141632d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj   case 0xAE: /* SCAS, no REP prefix */
141642d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj   case 0xAF:
141659c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      if (sorb != 0)
141669c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj         goto decode_failure; /* else dis_string_op asserts */
141672d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
141682d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      break;
1416964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1417064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1417164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0xFC: /* CLD */
14172eeb9ef8549a9c4aa15cbfbda52e20703d778fc61sewardj      stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
1417364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      DIP("cld\n");
1417464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      break;
1417564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
141761813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj   case 0xFD: /* STD */
141771813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
141781813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      DIP("std\n");
141791813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj      break;
141801813dbeb912870e9a544cae17a3fadbf8d2b0d55sewardj
14181bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj   case 0xF8: /* CLC */
14182bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj   case 0xF9: /* STC */
14183bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj   case 0xF5: /* CMC */
14184bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      t0 = newTemp(Ity_I32);
14185bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      t1 = newTemp(Ity_I32);
14186bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      assign( t0, mk_x86g_calculate_eflags_all() );
14187bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      switch (opc) {
14188bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         case 0xF8:
14189bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            assign( t1, binop(Iop_And32, mkexpr(t0),
14190bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj                                         mkU32(~X86G_CC_MASK_C)));
14191bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            DIP("clc\n");
14192bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            break;
14193bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         case 0xF9:
14194bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            assign( t1, binop(Iop_Or32, mkexpr(t0),
14195bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj                                        mkU32(X86G_CC_MASK_C)));
14196bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            DIP("stc\n");
14197bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            break;
14198bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         case 0xF5:
14199bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            assign( t1, binop(Iop_Xor32, mkexpr(t0),
14200bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj                                         mkU32(X86G_CC_MASK_C)));
14201bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            DIP("cmc\n");
14202bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            break;
14203bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         default:
14204bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj            vpanic("disInstr(x86)(clc/stc/cmc)");
14205bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      }
14206bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
14207bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14208bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
14209bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      /* Set NDEP even though it isn't used.  This makes redundant-PUT
14210bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj         elimination of previous stores to this field work better. */
14211bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14212bc210949baf2cb93f9cfbc1b1a0bb639bb6f9cdbsewardj      break;
142138229288c4fb1331c1e638bacdd55566e1caad9edsewardj
14214a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj   case 0xD6: /* SALC */
14215a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      t0 = newTemp(Ity_I32);
14216a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      t1 = newTemp(Ity_I32);
14217a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      assign( t0,  binop(Iop_And32,
14218a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj                         mk_x86g_calculate_eflags_c(),
14219a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj                         mkU32(1)) );
14220a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      assign( t1, binop(Iop_Sar32,
14221a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj                        binop(Iop_Shl32, mkexpr(t0), mkU8(31)),
14222a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj                        mkU8(31)) );
14223a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      putIReg(1, R_EAX, unop(Iop_32to8, mkexpr(t1)) );
14224a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      DIP("salc\n");
14225a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj      break;
14226a384eb941ac91bbec08fa5586130bb2f1a3a5438sewardj
142278229288c4fb1331c1e638bacdd55566e1caad9edsewardj   /* REPNE prefix insn */
142288229288c4fb1331c1e638bacdd55566e1caad9edsewardj   case 0xF2: {
14229068baa225ba96cd71e7852ba7588a93fae751b18sewardj      Addr32 eip_orig = guest_EIP_bbstart + delta_start;
142309c3b25a0a8c9d42dcf0a54c0e95a153c1f844922sewardj      if (sorb != 0) goto decode_failure;
142318229288c4fb1331c1e638bacdd55566e1caad9edsewardj      abyte = getIByte(delta); delta++;
142328229288c4fb1331c1e638bacdd55566e1caad9edsewardj
142338229288c4fb1331c1e638bacdd55566e1caad9edsewardj      if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
142348229288c4fb1331c1e638bacdd55566e1caad9edsewardj
142358229288c4fb1331c1e638bacdd55566e1caad9edsewardj      switch (abyte) {
142368229288c4fb1331c1e638bacdd55566e1caad9edsewardj      /* According to the Intel manual, "repne movs" should never occur, but
142378229288c4fb1331c1e638bacdd55566e1caad9edsewardj       * in practice it has happened, so allow for it here... */
14238180e8b39d5b4271e64634162986749c43536647csewardj      case 0xA4: sz = 1;   /* REPNE MOVS<sz> */
14239cea9662b02446234636e6e5fb269504c5f37fc20sewardj      case 0xA5:
14240c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondNZ, dis_MOVS, sz, eip_orig,
14241c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "repne movs" );
14242cea9662b02446234636e6e5fb269504c5f37fc20sewardj         break;
14243842dfb44f7eb453e1c0f3cd58687cff1c5696922sewardj
14244842dfb44f7eb453e1c0f3cd58687cff1c5696922sewardj      case 0xA6: sz = 1;   /* REPNE CMP<sz> */
14245842dfb44f7eb453e1c0f3cd58687cff1c5696922sewardj      case 0xA7:
14246c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondNZ, dis_CMPS, sz, eip_orig,
14247c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "repne cmps" );
14248842dfb44f7eb453e1c0f3cd58687cff1c5696922sewardj         break;
14249842dfb44f7eb453e1c0f3cd58687cff1c5696922sewardj
14250b69a6fa7c67203189f94f6dcc15e3c0fcddb472bsewardj      case 0xAA: sz = 1;   /* REPNE STOS<sz> */
14251b69a6fa7c67203189f94f6dcc15e3c0fcddb472bsewardj      case 0xAB:
14252c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondNZ, dis_STOS, sz, eip_orig,
14253c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "repne stos" );
14254b69a6fa7c67203189f94f6dcc15e3c0fcddb472bsewardj         break;
14255b69a6fa7c67203189f94f6dcc15e3c0fcddb472bsewardj
142568229288c4fb1331c1e638bacdd55566e1caad9edsewardj      case 0xAE: sz = 1;   /* REPNE SCAS<sz> */
142572d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      case 0xAF:
14258c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondNZ, dis_SCAS, sz, eip_orig,
14259c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "repne scas" );
142608229288c4fb1331c1e638bacdd55566e1caad9edsewardj         break;
142618229288c4fb1331c1e638bacdd55566e1caad9edsewardj
142628229288c4fb1331c1e638bacdd55566e1caad9edsewardj      default:
142638229288c4fb1331c1e638bacdd55566e1caad9edsewardj         goto decode_failure;
142648229288c4fb1331c1e638bacdd55566e1caad9edsewardj      }
142658229288c4fb1331c1e638bacdd55566e1caad9edsewardj      break;
142668229288c4fb1331c1e638bacdd55566e1caad9edsewardj   }
1426764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1426864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
1426964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      for the rest, it means REP) */
1427064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0xF3: {
14271068baa225ba96cd71e7852ba7588a93fae751b18sewardj      Addr32 eip_orig = guest_EIP_bbstart + delta_start;
1427264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      abyte = getIByte(delta); delta++;
1427364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1427464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
1427564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
14276c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj      if (sorb != 0 && abyte != 0x0F) goto decode_failure;
14277c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj
1427864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      switch (abyte) {
14279c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj      case 0x0F:
14280c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         switch (getIByte(delta)) {
14281c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         /* On older CPUs, TZCNT behaves the same as BSF.  */
14282c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         case 0xBC: /* REP BSF Gv,Ev */
14283c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj            delta = dis_bs_E_G ( sorb, sz, delta + 1, True );
14284c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj            break;
14285c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         /* On older CPUs, LZCNT behaves the same as BSR.  */
14286c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         case 0xBD: /* REP BSR Gv,Ev */
14287c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj            delta = dis_bs_E_G ( sorb, sz, delta + 1, False );
14288c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj            break;
14289c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         default:
14290c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj            goto decode_failure;
14291c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         }
14292c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj         break;
14293c8851af1a9c5a51180fd9c04bd8ac9033e98f270sewardj
1429464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      case 0xA4: sz = 1;   /* REP MOVS<sz> */
1429564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      case 0xA5:
14296c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondAlways, dis_MOVS, sz, eip_orig,
14297c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "rep movs" );
1429864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj         break;
1429964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1430064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      case 0xA6: sz = 1;   /* REPE CMP<sz> */
143012d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      case 0xA7:
14302c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondZ, dis_CMPS, sz, eip_orig,
14303c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "repe cmps" );
1430464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj         break;
1430564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1430664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      case 0xAA: sz = 1;   /* REP STOS<sz> */
1430764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      case 0xAB:
14308c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondAlways, dis_STOS, sz, eip_orig,
14309c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "rep stos" );
1431064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj         break;
14311576f323f29ae7a17a0f8fbce520c1a007b3b9966sewardj
14312dfb038d88735770985d7403304ed6ae3044646eesewardj      case 0xAC: sz = 1;   /* REP LODS<sz> */
14313dfb038d88735770985d7403304ed6ae3044646eesewardj      case 0xAD:
14314c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondAlways, dis_LODS, sz, eip_orig,
14315c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "rep lods" );
14316dfb038d88735770985d7403304ed6ae3044646eesewardj         break;
14317dfb038d88735770985d7403304ed6ae3044646eesewardj
14318576f323f29ae7a17a0f8fbce520c1a007b3b9966sewardj      case 0xAE: sz = 1;   /* REPE SCAS<sz> */
14319576f323f29ae7a17a0f8fbce520c1a007b3b9966sewardj      case 0xAF:
14320c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_REP_op ( &dres, X86CondZ, dis_SCAS, sz, eip_orig,
14321c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                             guest_EIP_bbstart+delta, "repe scas" );
14322576f323f29ae7a17a0f8fbce520c1a007b3b9966sewardj         break;
1432343b8df1af5787b806425aaa73aa363b6955c43cdsewardj
1432443b8df1af5787b806425aaa73aa363b6955c43cdsewardj      case 0x90:           /* REP NOP (PAUSE) */
1432543b8df1af5787b806425aaa73aa363b6955c43cdsewardj         /* a hint to the P4 re spin-wait loop */
1432643b8df1af5787b806425aaa73aa363b6955c43cdsewardj         DIP("rep nop (P4 pause)\n");
143277ec59f681fab67db360cfac258f6e07d5e394b8csewardj         /* "observe" the hint.  The Vex client needs to be careful not
143287ec59f681fab67db360cfac258f6e07d5e394b8csewardj            to cause very long delays as a result, though. */
14329c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jmp_lit(&dres, Ijk_Yield, ((Addr32)guest_EIP_bbstart)+delta);
14330c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
1433143b8df1af5787b806425aaa73aa363b6955c43cdsewardj         break;
1433243b8df1af5787b806425aaa73aa363b6955c43cdsewardj
143337d3d347d896b451d94d51232d4072551875014b7sewardj      case 0xC3:           /* REP RET -- same as normal ret? */
14334c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         dis_ret(&dres, 0);
143357d3d347d896b451d94d51232d4072551875014b7sewardj         DIP("rep ret\n");
143367d3d347d896b451d94d51232d4072551875014b7sewardj         break;
1433764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
1433864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      default:
1433964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj         goto decode_failure;
1434064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      }
1434164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      break;
1434264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   }
143430611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
143440611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   /* ------------------------ XCHG ----------------------- */
143450611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
14346c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj   /* XCHG reg,mem automatically asserts LOCK# even without a LOCK
143471fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj      prefix; hence it must be translated with an IRCAS (at least, the
143481fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj      memory variant). */
143490611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x86: /* XCHG Gb,Eb */
143500611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      sz = 1;
143510611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      /* Fall through ... */
143520611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x87: /* XCHG Gv,Ev */
143530611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      modrm = getIByte(delta);
143540611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      ty = szToITy(sz);
143550611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      t1 = newTemp(ty); t2 = newTemp(ty);
143560611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      if (epartIsReg(modrm)) {
143575bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         assign(t1, getIReg(sz, eregOfRM(modrm)));
143585bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         assign(t2, getIReg(sz, gregOfRM(modrm)));
143595bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         putIReg(sz, gregOfRM(modrm), mkexpr(t1));
143605bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         putIReg(sz, eregOfRM(modrm), mkexpr(t2));
143610611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         delta++;
143620611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         DIP("xchg%c %s, %s\n",
143630611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj             nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
143640611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                            nameIReg(sz,eregOfRM(modrm)));
143650611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      } else {
14366e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         *expect_CAS = True;
143670c12ea83187de020a5484b4327e2427ea3451380sewardj         addr = disAMode ( &alen, sorb, delta, dis_buf );
143685bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         assign( t1, loadLE(ty,mkexpr(addr)) );
143695bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         assign( t2, getIReg(sz,gregOfRM(modrm)) );
14370e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         casLE( mkexpr(addr),
14371e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
143725bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
143735bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         delta += alen;
143740611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         DIP("xchg%c %s, %s\n", nameISize(sz),
143750611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj                                nameIReg(sz,gregOfRM(modrm)), dis_buf);
143760611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      }
143770611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
14378e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
14379e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x90: /* XCHG eAX,eAX */
14380e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      DIP("nop\n");
14381e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      break;
1438264e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x91: /* XCHG eAX,eCX */
1438364e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x92: /* XCHG eAX,eDX */
1438464e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x93: /* XCHG eAX,eBX */
1438564e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x94: /* XCHG eAX,eSP */
1438664e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x95: /* XCHG eAX,eBP */
1438764e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x96: /* XCHG eAX,eSI */
1438864e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj   case 0x97: /* XCHG eAX,eDI */
1438964e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
1439064e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj      break;
1439164e1d656188ead7ec5af83b3fb3effef02ae73ecsewardj
14392048de4da3c356e4dcdba7c693d850027b7d67c34sewardj   /* ------------------------ XLAT ----------------------- */
14393048de4da3c356e4dcdba7c693d850027b7d67c34sewardj
14394048de4da3c356e4dcdba7c693d850027b7d67c34sewardj   case 0xD7: /* XLAT */
14395048de4da3c356e4dcdba7c693d850027b7d67c34sewardj      if (sz != 4) goto decode_failure; /* sz == 2 is also allowed (0x66) */
14396048de4da3c356e4dcdba7c693d850027b7d67c34sewardj      putIReg(
14397048de4da3c356e4dcdba7c693d850027b7d67c34sewardj         1,
14398048de4da3c356e4dcdba7c693d850027b7d67c34sewardj         R_EAX/*AL*/,
14399048de4da3c356e4dcdba7c693d850027b7d67c34sewardj         loadLE(Ity_I8,
14400048de4da3c356e4dcdba7c693d850027b7d67c34sewardj                handleSegOverride(
14401048de4da3c356e4dcdba7c693d850027b7d67c34sewardj                   sorb,
14402048de4da3c356e4dcdba7c693d850027b7d67c34sewardj                   binop(Iop_Add32,
14403048de4da3c356e4dcdba7c693d850027b7d67c34sewardj                         getIReg(4, R_EBX),
14404048de4da3c356e4dcdba7c693d850027b7d67c34sewardj                         unop(Iop_8Uto32, getIReg(1, R_EAX/*AL*/))))));
14405048de4da3c356e4dcdba7c693d850027b7d67c34sewardj
14406048de4da3c356e4dcdba7c693d850027b7d67c34sewardj      DIP("xlat%c [ebx]\n", nameISize(sz));
14407048de4da3c356e4dcdba7c693d850027b7d67c34sewardj      break;
14408d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj
14409d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   /* ------------------------ IN / OUT ----------------------- */
14410d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj
14411d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xE4: /* IN imm8, AL */
14412d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      sz = 1;
14413d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14414d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      abyte = getIByte(delta); delta++;
14415d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign(t1, mkU32( abyte & 0xFF ));
14416d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX));
14417d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_IN;
14418d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xE5: /* IN imm8, eAX */
14419d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      vassert(sz == 2 || sz == 4);
14420d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14421d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      abyte = getIByte(delta); delta++;
14422d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign(t1, mkU32( abyte & 0xFF ));
14423d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX));
14424d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_IN;
14425d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xEC: /* IN %DX, AL */
14426d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      sz = 1;
14427d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14428d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14429d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14430d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj                                         nameIReg(sz,R_EAX));
14431d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_IN;
14432d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xED: /* IN %DX, eAX */
14433d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      vassert(sz == 2 || sz == 4);
14434d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14435d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14436d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14437d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj                                         nameIReg(sz,R_EAX));
14438d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_IN;
14439d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   do_IN: {
14440d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      /* At this point, sz indicates the width, and t1 is a 32-bit
14441d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj         value giving port number. */
14442d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      IRDirty* d;
14443d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      vassert(sz == 1 || sz == 2 || sz == 4);
14444d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      ty = szToITy(sz);
14445d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t2 = newTemp(Ity_I32);
14446d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      d = unsafeIRDirty_1_N(
14447d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             t2,
14448d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             0/*regparms*/,
14449d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             "x86g_dirtyhelper_IN",
14450d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             &x86g_dirtyhelper_IN,
14451d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             mkIRExprVec_2( mkexpr(t1), mkU32(sz) )
14452d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj          );
14453d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      /* do the call, dumping the result in t2. */
14454d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      stmt( IRStmt_Dirty(d) );
14455d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      putIReg(sz, R_EAX, narrowTo( ty, mkexpr(t2) ) );
14456d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      break;
14457d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   }
14458d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj
14459d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xE6: /* OUT AL, imm8 */
14460d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      sz = 1;
14461d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14462d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      abyte = getIByte(delta); delta++;
14463d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign( t1, mkU32( abyte & 0xFF ) );
14464d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte);
14465d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_OUT;
14466d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xE7: /* OUT eAX, imm8 */
14467d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      vassert(sz == 2 || sz == 4);
14468d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14469d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      abyte = getIByte(delta); delta++;
14470d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign( t1, mkU32( abyte & 0xFF ) );
14471d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte);
14472d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_OUT;
14473d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xEE: /* OUT AL, %DX */
14474d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      sz = 1;
14475d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14476d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14477d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14478d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj                                          nameIReg(2,R_EDX));
14479d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_OUT;
14480d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   case 0xEF: /* OUT eAX, %DX */
14481d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      vassert(sz == 2 || sz == 4);
14482d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      t1 = newTemp(Ity_I32);
14483d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14484d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14485d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj                                          nameIReg(2,R_EDX));
14486d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      goto do_OUT;
14487d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   do_OUT: {
14488d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      /* At this point, sz indicates the width, and t1 is a 32-bit
14489d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj         value giving port number. */
14490d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      IRDirty* d;
14491d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      vassert(sz == 1 || sz == 2 || sz == 4);
14492d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      ty = szToITy(sz);
14493d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      d = unsafeIRDirty_0_N(
14494d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             0/*regparms*/,
14495d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             "x86g_dirtyhelper_OUT",
14496d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             &x86g_dirtyhelper_OUT,
14497d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj             mkIRExprVec_3( mkexpr(t1),
14498d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj                            widenUto32( getIReg(sz, R_EAX) ),
14499d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj                            mkU32(sz) )
14500d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj          );
14501d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      stmt( IRStmt_Dirty(d) );
14502d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj      break;
14503d14c5702cd2a0b15a66119ec1a6d68e4840a0dd5sewardj   }
145040611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
145050611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   /* ------------------------ (Grp1 extensions) ---------- */
145060611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
14507792d771d513e1ba805983848bf5873a75a44b3b0sewardj   case 0x82: /* Grp1 Ib,Eb too.  Apparently this is the same as
14508792d771d513e1ba805983848bf5873a75a44b3b0sewardj                 case 0x80, but only in 32-bit mode. */
14509792d771d513e1ba805983848bf5873a75a44b3b0sewardj      /* fallthru */
145100611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   case 0x80: /* Grp1 Ib,Eb */
145110611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      modrm = getIByte(delta);
145120611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      am_sz = lengthAMode(delta);
145130611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      sz    = 1;
145140611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      d_sz  = 1;
14515c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      d32   = getUChar(delta + am_sz);
14516e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
145170611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
14518e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj
14519e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj   case 0x81: /* Grp1 Iv,Ev */
14520e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      modrm = getIByte(delta);
14521e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      am_sz = lengthAMode(delta);
14522e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      d_sz  = sz;
14523e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      d32   = getUDisp(d_sz, delta + am_sz);
14524e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
14525e05c42c99a8e01d05096482afdaa3e7460265dc2sewardj      break;
14526d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14527d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj   case 0x83: /* Grp1 Ib,Ev */
14528d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      modrm = getIByte(delta);
14529d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      am_sz = lengthAMode(delta);
14530d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      d_sz  = 1;
14531d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      d32   = getSDisp8(delta + am_sz);
14532e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
14533d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj      break;
14534d1061ab20eb3906487f55ccfd0d5c67b86d7b0c4sewardj
14535c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   /* ------------------------ (Grp2 extensions) ---------- */
14536c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
14537d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xC0: { /* Grp2 Ib,Eb */
14538d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14539c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      modrm = getIByte(delta);
14540c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      am_sz = lengthAMode(delta);
14541c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      d_sz  = 1;
14542180e8b39d5b4271e64634162986749c43536647csewardj      d32   = getUChar(delta + am_sz);
14543c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      sz    = 1;
145446d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14545d51dc81599cba69ddc133f56c743205330f9dc40sewardj                         mkU8(d32 & 0xFF), NULL, &decode_OK );
14546d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14547d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14548c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
14549d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14550d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xC1: { /* Grp2 Ib,Ev */
14551d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14552c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      modrm = getIByte(delta);
14553e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      am_sz = lengthAMode(delta);
14554e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      d_sz  = 1;
14555180e8b39d5b4271e64634162986749c43536647csewardj      d32   = getUChar(delta + am_sz);
145566d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14557d51dc81599cba69ddc133f56c743205330f9dc40sewardj                         mkU8(d32 & 0xFF), NULL, &decode_OK );
14558d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14559d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14560e90ad6abbe540a5b3ffa68ba0c641ced77c20211sewardj      break;
14561d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14562d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xD0: { /* Grp2 1,Eb */
14563d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14564180e8b39d5b4271e64634162986749c43536647csewardj      modrm = getIByte(delta);
14565180e8b39d5b4271e64634162986749c43536647csewardj      am_sz = lengthAMode(delta);
14566180e8b39d5b4271e64634162986749c43536647csewardj      d_sz  = 0;
14567180e8b39d5b4271e64634162986749c43536647csewardj      d32   = 1;
14568180e8b39d5b4271e64634162986749c43536647csewardj      sz    = 1;
14569180e8b39d5b4271e64634162986749c43536647csewardj      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14570d51dc81599cba69ddc133f56c743205330f9dc40sewardj                         mkU8(d32), NULL, &decode_OK );
14571d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14572d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14573180e8b39d5b4271e64634162986749c43536647csewardj      break;
14574d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14575d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xD1: { /* Grp2 1,Ev */
14576d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14577c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      modrm = getUChar(delta);
14578c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      am_sz = lengthAMode(delta);
14579c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      d_sz  = 0;
14580c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      d32   = 1;
145816d2638e5edd8849e036f235d42a23c959e3bc3d8sewardj      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14582d51dc81599cba69ddc133f56c743205330f9dc40sewardj                         mkU8(d32), NULL, &decode_OK );
14583d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14584d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14585c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
14586d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14587d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xD2: { /* Grp2 CL,Eb */
14588d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
145898c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      modrm = getUChar(delta);
145908c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      am_sz = lengthAMode(delta);
145918c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      d_sz  = 0;
145928c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      sz    = 1;
145938c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14594d51dc81599cba69ddc133f56c743205330f9dc40sewardj                         getIReg(1,R_ECX), "%cl", &decode_OK );
14595d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14596d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
145978c7f1abe9e022f6382634efea09c9cac89ec6336sewardj      break;
14598d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14599d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xD3: { /* Grp2 CL,Ev */
14600d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
146019334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      modrm = getIByte(delta);
146029334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      am_sz = lengthAMode(delta);
146039334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      d_sz  = 0;
146049334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
14605d51dc81599cba69ddc133f56c743205330f9dc40sewardj                         getIReg(1,R_ECX), "%cl", &decode_OK );
14606d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14607d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
146089334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      break;
14609d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
146109334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
14611940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj   /* ------------------------ (Grp3 extensions) ---------- */
14612940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
14613d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xF6: { /* Grp3 Eb */
14614d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14615e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp3 ( sorb, pfx_lock, 1, delta, &decode_OK );
14616d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14617d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14618940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
14619d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14620d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xF7: { /* Grp3 Ev */
14621d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14622e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp3 ( sorb, pfx_lock, sz, delta, &decode_OK );
14623d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14624d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14625940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      break;
14626d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14627940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
14628c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj   /* ------------------------ (Grp4 extensions) ---------- */
14629c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj
14630d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xFE: { /* Grp4 Eb */
14631d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14632e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp4 ( sorb, pfx_lock, delta, &decode_OK );
14633d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14634d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
14635c2ac51e1edd7a5be9c034ae358747319fb5cbd22sewardj      break;
14636d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
146370611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
146380611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj   /* ------------------------ (Grp5 extensions) ---------- */
146390611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj
14640d51dc81599cba69ddc133f56c743205330f9dc40sewardj   case 0xFF: { /* Grp5 Ev */
14641d51dc81599cba69ddc133f56c743205330f9dc40sewardj      Bool decode_OK = True;
14642e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      delta = dis_Grp5 ( sorb, pfx_lock, sz, delta, &dres, &decode_OK );
14643d51dc81599cba69ddc133f56c743205330f9dc40sewardj      if (!decode_OK)
14644d51dc81599cba69ddc133f56c743205330f9dc40sewardj         goto decode_failure;
146450611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      break;
14646d51dc81599cba69ddc133f56c743205330f9dc40sewardj   }
14647e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
14648e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   /* ------------------------ Escapes to 2-byte opcodes -- */
14649e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
14650e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   case 0x0F: {
14651e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      opc = getIByte(delta); delta++;
14652e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      switch (opc) {
14653e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
14654490ad3820487e34854c46befcc9c755d6afc2519sewardj      /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
14655490ad3820487e34854c46befcc9c755d6afc2519sewardj
14656490ad3820487e34854c46befcc9c755d6afc2519sewardj      case 0xBA: { /* Grp8 Ib,Ev */
14657490ad3820487e34854c46befcc9c755d6afc2519sewardj         Bool decode_OK = False;
14658490ad3820487e34854c46befcc9c755d6afc2519sewardj         modrm = getUChar(delta);
14659490ad3820487e34854c46befcc9c755d6afc2519sewardj         am_sz = lengthAMode(delta);
14660490ad3820487e34854c46befcc9c755d6afc2519sewardj         d32   = getSDisp8(delta + am_sz);
14661e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         delta = dis_Grp8_Imm ( sorb, pfx_lock, delta, modrm,
14662e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                                am_sz, sz, d32, &decode_OK );
14663490ad3820487e34854c46befcc9c755d6afc2519sewardj         if (!decode_OK)
14664490ad3820487e34854c46befcc9c755d6afc2519sewardj            goto decode_failure;
14665490ad3820487e34854c46befcc9c755d6afc2519sewardj         break;
14666490ad3820487e34854c46befcc9c755d6afc2519sewardj      }
14667ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
14668ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
14669ce646f23d71ac432c340667387aa4a5ce7d18099sewardj
14670ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      case 0xBC: /* BSF Gv,Ev */
14671ce646f23d71ac432c340667387aa4a5ce7d18099sewardj         delta = dis_bs_E_G ( sorb, sz, delta, True );
14672ce646f23d71ac432c340667387aa4a5ce7d18099sewardj         break;
14673ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      case 0xBD: /* BSR Gv,Ev */
14674ce646f23d71ac432c340667387aa4a5ce7d18099sewardj         delta = dis_bs_E_G ( sorb, sz, delta, False );
14675ce646f23d71ac432c340667387aa4a5ce7d18099sewardj         break;
146761c4208f37f1d835e655967ba70f5d4f4f6686392sewardj
146771c4208f37f1d835e655967ba70f5d4f4f6686392sewardj      /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
146781c4208f37f1d835e655967ba70f5d4f4f6686392sewardj
146791c4208f37f1d835e655967ba70f5d4f4f6686392sewardj      case 0xC8: /* BSWAP %eax */
146801c4208f37f1d835e655967ba70f5d4f4f6686392sewardj      case 0xC9:
146811c4208f37f1d835e655967ba70f5d4f4f6686392sewardj      case 0xCA:
14682b4666cfa1661348b621b88ab2309cc82d82cc13dsewardj      case 0xCB:
14683b4666cfa1661348b621b88ab2309cc82d82cc13dsewardj      case 0xCC:
14684b4666cfa1661348b621b88ab2309cc82d82cc13dsewardj      case 0xCD:
146851c4208f37f1d835e655967ba70f5d4f4f6686392sewardj      case 0xCE:
146861c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case 0xCF: /* BSWAP %edi */
146871c4208f37f1d835e655967ba70f5d4f4f6686392sewardj         /* AFAICS from the Intel docs, this only exists at size 4. */
14688021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         if (sz != 4) goto decode_failure;
14689021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj
146901c4208f37f1d835e655967ba70f5d4f4f6686392sewardj         t1 = newTemp(Ity_I32);
146911c4208f37f1d835e655967ba70f5d4f4f6686392sewardj         assign( t1, getIReg(4, opc-0xC8) );
14692021f6b420c3ce127091cdf3e1facbfabbe92100fsewardj         t2 = math_BSWAP(t1, Ity_I32);
146931c4208f37f1d835e655967ba70f5d4f4f6686392sewardj
146941c4208f37f1d835e655967ba70f5d4f4f6686392sewardj         putIReg(4, opc-0xC8, mkexpr(t2));
146951c4208f37f1d835e655967ba70f5d4f4f6686392sewardj         DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
146961c4208f37f1d835e655967ba70f5d4f4f6686392sewardj         break;
146971c4208f37f1d835e655967ba70f5d4f4f6686392sewardj
146981c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
146991c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj
147001c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case 0xA3: /* BT Gv,Ev */
147010283430ee809d645864ddd2da5f450f88142b4cdsewardj         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpNone );
147021c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj         break;
14703e6709111d4af7becab76be5971eea568074174cdsewardj      case 0xB3: /* BTR Gv,Ev */
147040283430ee809d645864ddd2da5f450f88142b4cdsewardj         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpReset );
14705e6709111d4af7becab76be5971eea568074174cdsewardj         break;
147061c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj      case 0xAB: /* BTS Gv,Ev */
147070283430ee809d645864ddd2da5f450f88142b4cdsewardj         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpSet );
147081c6f991d4f9071ff65fe4b36b7dc519af38398b2sewardj         break;
147094963a42df83976b446e204c7f1eb587021bd94a3sewardj      case 0xBB: /* BTC Gv,Ev */
147100283430ee809d645864ddd2da5f450f88142b4cdsewardj         delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpComp );
147114963a42df83976b446e204c7f1eb587021bd94a3sewardj         break;
14712458a6f8809554fc459d90043e032f7c579620c97sewardj
14713458a6f8809554fc459d90043e032f7c579620c97sewardj      /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
14714458a6f8809554fc459d90043e032f7c579620c97sewardj
147152d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      case 0x40:
147162d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      case 0x41:
14717458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
14718458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
14719458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
14720458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
14721458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
14722458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
14723ce646f23d71ac432c340667387aa4a5ce7d18099sewardj      case 0x48: /* CMOVSb (cmov negative) */
14724458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x49: /* CMOVSb (cmov not negative) */
147252d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      case 0x4A: /* CMOVP (cmov parity even) */
147262d4c3a0fe494f7201b3eac54ec2c66774c4b88b5sewardj      case 0x4B: /* CMOVNP (cmov parity odd) */
14727458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
14728458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
14729458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
14730458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
147312a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
14732458a6f8809554fc459d90043e032f7c579620c97sewardj         break;
14733458a6f8809554fc459d90043e032f7c579620c97sewardj
14734458a6f8809554fc459d90043e032f7c579620c97sewardj      /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
14735458a6f8809554fc459d90043e032f7c579620c97sewardj
14736c744e870f0831fb929a3853cdf42e6f1d3ff9fb6sewardj      case 0xB0: /* CMPXCHG Gb,Eb */
14737e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         delta = dis_cmpxchg_G_E ( sorb, pfx_lock, 1, delta );
14738c744e870f0831fb929a3853cdf42e6f1d3ff9fb6sewardj         break;
14739458a6f8809554fc459d90043e032f7c579620c97sewardj      case 0xB1: /* CMPXCHG Gv,Ev */
14740e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         delta = dis_cmpxchg_G_E ( sorb, pfx_lock, sz, delta );
14741458a6f8809554fc459d90043e032f7c579620c97sewardj         break;
14742300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14743300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj      case 0xC7: { /* CMPXCHG8B Gv (0F C7 /1) */
14744e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp expdHi    = newTemp(Ity_I32);
14745e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp expdLo    = newTemp(Ity_I32);
14746e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp dataHi    = newTemp(Ity_I32);
14747e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp dataLo    = newTemp(Ity_I32);
14748e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp oldHi     = newTemp(Ity_I32);
14749e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp oldLo     = newTemp(Ity_I32);
14750300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         IRTemp flags_old = newTemp(Ity_I32);
14751300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         IRTemp flags_new = newTemp(Ity_I32);
14752e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         IRTemp success   = newTemp(Ity_I1);
14753e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
14754e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* Translate this using a DCAS, even if there is no LOCK
14755e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            prefix.  Life is too short to bother with generating two
14756e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            different translations for the with/without-LOCK-prefix
14757e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            cases. */
14758e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         *expect_CAS = True;
14759300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14760300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj	 /* Decode, and generate address. */
14761e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         if (sz != 4) goto decode_failure;
14762300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         modrm = getIByte(delta);
14763300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         if (epartIsReg(modrm)) goto decode_failure;
14764300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         if (gregOfRM(modrm) != 1) goto decode_failure;
14765300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         addr = disAMode ( &alen, sorb, delta, dis_buf );
14766300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         delta += alen;
14767300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14768e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* Get the expected and new values. */
14769e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         assign( expdHi, getIReg(4,R_EDX) );
14770e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         assign( expdLo, getIReg(4,R_EAX) );
14771e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         assign( dataHi, getIReg(4,R_ECX) );
14772e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         assign( dataLo, getIReg(4,R_EBX) );
14773e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
14774e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* Do the DCAS */
14775e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         stmt( IRStmt_CAS(
14776e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                  mkIRCAS( oldHi, oldLo,
14777e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           Iend_LE, mkexpr(addr),
14778e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           mkexpr(expdHi), mkexpr(expdLo),
14779e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                           mkexpr(dataHi), mkexpr(dataLo)
14780e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj               )));
14781e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
14782e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* success when oldHi:oldLo == expdHi:expdLo */
14783e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         assign( success,
147841fb8c92e9b0882ebbd53c04c69ebad7efb1cd3d8sewardj                 binop(Iop_CasCmpEQ32,
14785e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                       binop(Iop_Or32,
14786e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                             binop(Iop_Xor32, mkexpr(oldHi), mkexpr(expdHi)),
14787e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                             binop(Iop_Xor32, mkexpr(oldLo), mkexpr(expdLo))
14788e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                       ),
14789e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                       mkU32(0)
14790e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                 ));
14791e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
14792e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* If the DCAS is successful, that is to say oldHi:oldLo ==
14793e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            expdHi:expdLo, then put expdHi:expdLo back in EDX:EAX,
14794e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            which is where they came from originally.  Both the actual
14795e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            contents of these two regs, and any shadow values, are
14796e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            unchanged.  If the DCAS fails then we're putting into
14797e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            EDX:EAX the value seen in memory. */
14798e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         putIReg(4, R_EDX,
1479999dd03e04a6914d90d5fee727d61d76905334becflorian                    IRExpr_ITE( mkexpr(success),
1480099dd03e04a6914d90d5fee727d61d76905334becflorian                                mkexpr(expdHi), mkexpr(oldHi)
14801e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                ));
14802e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         putIReg(4, R_EAX,
1480399dd03e04a6914d90d5fee727d61d76905334becflorian                    IRExpr_ITE( mkexpr(success),
1480499dd03e04a6914d90d5fee727d61d76905334becflorian                                mkexpr(expdLo), mkexpr(oldLo)
14805e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                ));
14806e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
14807e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         /* Copy the success bit into the Z flag and leave the others
14808e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj            unchanged */
14809300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         assign( flags_old, widenUto32(mk_x86g_calculate_eflags_all()));
14810300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         assign(
14811300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj            flags_new,
14812300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj            binop(Iop_Or32,
14813300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj                  binop(Iop_And32, mkexpr(flags_old),
14814300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj                                   mkU32(~X86G_CC_MASK_Z)),
14815300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj                  binop(Iop_Shl32,
14816300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj                        binop(Iop_And32,
14817e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj                              unop(Iop_1Uto32, mkexpr(success)), mkU32(1)),
14818300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj                        mkU8(X86G_CC_SHIFT_Z)) ));
14819300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14820300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
14821300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
14822300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14823300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         /* Set NDEP even though it isn't used.  This makes
14824300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj            redundant-PUT elimination of previous stores to this field
14825300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj            work better. */
14826300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14827300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14828300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj         /* Sheesh.  Aren't you glad it was me and not you that had to
14829300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj	    write and validate all this grunge? */
14830300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14831300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj	 DIP("cmpxchg8b %s\n", dis_buf);
14832300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj	 break;
14833300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj      }
14834300bb87d70ed2585b3657c3ff2bdb028b470fb6asewardj
14835588ea765122c1ecb97991eea513b12504e35d55esewardj      /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
14836588ea765122c1ecb97991eea513b12504e35d55esewardj
148377cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj      case 0xA2: { /* CPUID */
148387cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         /* Uses dirty helper:
148399df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj               void dirtyhelper_CPUID_sse[012] ( VexGuestX86State* )
148407cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj            declared to mod eax, wr ebx, ecx, edx
148417cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         */
148429df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         IRDirty* d     = NULL;
148439df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         void*    fAddr = NULL;
1484455085f8680acc89d727e321f3b34cae1a8c4093aflorian         const HChar* fName = NULL;
148455117ce116f47141cb23d1b49cc826e19323add97sewardj         if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2) {
148465117ce116f47141cb23d1b49cc826e19323add97sewardj            fName = "x86g_dirtyhelper_CPUID_sse2";
148475117ce116f47141cb23d1b49cc826e19323add97sewardj            fAddr = &x86g_dirtyhelper_CPUID_sse2;
148485117ce116f47141cb23d1b49cc826e19323add97sewardj         }
148495117ce116f47141cb23d1b49cc826e19323add97sewardj         else
148505117ce116f47141cb23d1b49cc826e19323add97sewardj         if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE1) {
148515117ce116f47141cb23d1b49cc826e19323add97sewardj            fName = "x86g_dirtyhelper_CPUID_sse1";
148525117ce116f47141cb23d1b49cc826e19323add97sewardj            fAddr = &x86g_dirtyhelper_CPUID_sse1;
148535117ce116f47141cb23d1b49cc826e19323add97sewardj         }
148545117ce116f47141cb23d1b49cc826e19323add97sewardj         else
148556c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         if (archinfo->hwcaps & VEX_HWCAPS_X86_MMXEXT) {
148566c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            fName = "x86g_dirtyhelper_CPUID_mmxext";
148576c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw            fAddr = &x86g_dirtyhelper_CPUID_mmxext;
148586c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         }
148596c65c12ecf69436421ebc1b5637ee13bb4aaf41emjw         else
148605117ce116f47141cb23d1b49cc826e19323add97sewardj         if (archinfo->hwcaps == 0/*no SSE*/) {
148615117ce116f47141cb23d1b49cc826e19323add97sewardj            fName = "x86g_dirtyhelper_CPUID_sse0";
148625117ce116f47141cb23d1b49cc826e19323add97sewardj            fAddr = &x86g_dirtyhelper_CPUID_sse0;
148635117ce116f47141cb23d1b49cc826e19323add97sewardj         } else
148645117ce116f47141cb23d1b49cc826e19323add97sewardj            vpanic("disInstr(x86)(cpuid)");
148655117ce116f47141cb23d1b49cc826e19323add97sewardj
148669df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         vassert(fName); vassert(fAddr);
148679df271d97c0f79a58a8eabdcfbe6f8bf4d17876asewardj         d = unsafeIRDirty_0_N ( 0/*regparms*/,
148689041956f39c57e265122ed0a71061dea1e554edcflorian                                 fName, fAddr, mkIRExprVec_1(IRExpr_BBPTR()) );
148697cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         /* declare guest state effects */
148707cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->nFxState = 4;
14871c9069f2908814843e9a4da00da9c8905440195a6sewardj         vex_bzero(&d->fxState, sizeof(d->fxState));
148727cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[0].fx     = Ifx_Modify;
148737cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[0].offset = OFFB_EAX;
148747cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[0].size   = 4;
148757cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[1].fx     = Ifx_Write;
148767cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[1].offset = OFFB_EBX;
148777cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[1].size   = 4;
1487832bfd3e057bf3e0b215b1d234398b4d7791eba9asewardj         d->fxState[2].fx     = Ifx_Modify;
148797cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[2].offset = OFFB_ECX;
148807cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[2].size   = 4;
148817cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[3].fx     = Ifx_Write;
148827cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[3].offset = OFFB_EDX;
148837cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         d->fxState[3].size   = 4;
148847cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         /* execute the dirty call, side-effecting guest state */
148857cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj         stmt( IRStmt_Dirty(d) );
1488655860d8f317d0cbd28d56734766bca1a330f2362sewardj         /* CPUID is a serialising insn.  So, just in case someone is
1488755860d8f317d0cbd28d56734766bca1a330f2362sewardj            using it as a memory fence ... */
14888c4356f0d3c74fc2622dbeed79c6c1045fc519f72sewardj         stmt( IRStmt_MBE(Imbe_Fence) );
14889517a7d602150b0701ebb32fa837374da1c3c80c8sewardj         DIP("cpuid\n");
14890588ea765122c1ecb97991eea513b12504e35d55esewardj         break;
148917cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj      }
148927cb49d78b0f97c1f83ac95a02f4d044a4dd3f194sewardj
148935bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj//--          if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
148945bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj//--             goto decode_failure;
14895c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14896c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          t1 = newTemp(cb);
14897c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          t2 = newTemp(cb);
14898c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          t3 = newTemp(cb);
14899c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          t4 = newTemp(cb);
14900c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr0(cb, CALLM_S, 0);
14901c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14902c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, GET,   4, ArchReg, R_EAX, TempReg, t1);
14903c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, PUSH,  4, TempReg, t1);
14904c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14905c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, MOV,   4, Literal, 0, TempReg, t2);
14906c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uLiteral(cb, 0);
14907c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, PUSH,  4, TempReg, t2);
14908c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14909c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, MOV,   4, Literal, 0, TempReg, t3);
14910c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uLiteral(cb, 0);
14911c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, PUSH,  4, TempReg, t3);
14912c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14913c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, MOV,   4, Literal, 0, TempReg, t4);
14914c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uLiteral(cb, 0);
14915c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, PUSH,  4, TempReg, t4);
14916c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14917c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, CALLM, 0, Lit16,   VGOFF_(helper_CPUID));
14918c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
14919c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14920c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, POP,   4, TempReg, t4);
14921c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, PUT,   4, TempReg, t4, ArchReg, R_EDX);
14922c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14923c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, POP,   4, TempReg, t3);
14924c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, PUT,   4, TempReg, t3, ArchReg, R_ECX);
14925c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14926c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, POP,   4, TempReg, t2);
14927c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, PUT,   4, TempReg, t2, ArchReg, R_EBX);
14928c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14929c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr1(cb, POP,   4, TempReg, t1);
14930c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, PUT,   4, TempReg, t1, ArchReg, R_EAX);
14931c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14932c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr0(cb, CALLM_E, 0);
14933c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          DIP("cpuid\n");
14934c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          break;
14935c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
149369334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
149379334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj
149389334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj      case 0xB6: /* MOVZXb Eb,Gv */
149396ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj         if (sz != 2 && sz != 4)
149406ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj            goto decode_failure;
149416ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj         delta = dis_movx_E_G ( sorb, delta, 1, sz, False );
149429334b0f718b0f4e7eedae61efa9a9074c8c7e10dsewardj         break;
149436ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj
14944940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj      case 0xB7: /* MOVZXw Ew,Gv */
149456ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj         if (sz != 4)
149466ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj            goto decode_failure;
14947940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
14948940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj         break;
14949940e8c989d1211979404e1ebff6a3bf3d7665fb5sewardj
149500611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj      case 0xBE: /* MOVSXb Eb,Gv */
149516ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj         if (sz != 2 && sz != 4)
149526ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj            goto decode_failure;
149536ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj         delta = dis_movx_E_G ( sorb, delta, 1, sz, True );
149540611d80c6de8db5b2cdc0ae7bb04dd8c70ee1087sewardj         break;
149556ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj
149567ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj      case 0xBF: /* MOVSXw Ew,Gv */
1495733ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         if (sz != 4 && /* accept movsww, sigh, see #250799 */sz != 2)
149586ba982f95fdaaba7ec9081de2ec8031099ca2925sewardj            goto decode_failure;
1495933ca4acf01e29bf8ec4adce63aa5925d549c105esewardj         delta = dis_movx_E_G ( sorb, delta, 2, sz, True );
149607ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj         break;
149617ed2295459ac5e788a98dd5570fef0d4645c27d4sewardj
14962c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
14963c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--
14964c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--       case 0xC3: /* MOVNTI Gv,Ev */
14965c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          vg_assert(sz == 4);
14966c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          modrm = getUChar(eip);
14967c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          vg_assert(!epartIsReg(modrm));
14968c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          t1 = newTemp(cb);
14969c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
14970c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          pair = disAMode ( cb, sorb, eip, dis_buf );
14971c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          t2 = LOW24(pair);
14972c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          eip += HI8(pair);
14973c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
14974c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
14975c9a6570e86f4252f8a486b4df48de8710d357a4asewardj//--          break;
14976cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
14977cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj      /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
14978cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj
14979cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj      case 0xAF: /* IMUL Ev, Gv */
149802a2ba8b72b4e467292c33cec23dee90cbf078e5dsewardj         delta = dis_mul_E_G ( sorb, sz, delta );
14981cf780b4c356a274cc48a6829963f8bc79a1b34e8sewardj         break;
14982e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
14983ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj      /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
14984ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj
14985ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj      case 0x1F:
14986ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj         modrm = getUChar(delta);
14987ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj         if (epartIsReg(modrm)) goto decode_failure;
14988ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj         addr = disAMode ( &alen, sorb, delta, dis_buf );
14989ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj         delta += alen;
14990ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj         DIP("nop%c %s\n", nameISize(sz), dis_buf);
14991ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj         break;
14992ec387ca7a670b5fc708aa4dc1c310b7d91156689sewardj
14993e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
14994e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x80:
14995e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x81:
14996e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x82: /* JBb/JNAEb (jump below) */
14997e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x83: /* JNBb/JAEb (jump not below) */
14998e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x84: /* JZb/JEb (jump zero) */
14999e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x85: /* JNZb/JNEb (jump not zero) */
15000e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x86: /* JBEb/JNAb (jump below or equal) */
15001e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x87: /* JNBEb/JAb (jump not below or equal) */
15002e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x88: /* JSb (jump negative) */
15003e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x89: /* JSb (jump not negative) */
15004e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x8A: /* JP (jump parity even) */
15005e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x8B: /* JNP/JPO (jump parity odd) */
15006e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x8C: /* JLb/JNGEb (jump less) */
15007e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x8D: /* JGEb/JNLb (jump greater or equal) */
15008e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x8E: /* JLEb/JNGb (jump less or equal) */
15009e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      case 0x8F: /* JGb/JNLEb (jump greater) */
15010984d9b164dd17f07e603c41fe1e506e641e57d18sewardj       { Int    jmpDelta;
1501155085f8680acc89d727e321f3b34cae1a8c4093aflorian         const HChar* comment  = "";
15012984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         jmpDelta = (Int)getUDisp32(delta);
15013984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         d32 = (((Addr32)guest_EIP_bbstart)+delta+4) + jmpDelta;
15014e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj         delta += 4;
15015984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         if (resteerCisOk
15016984d9b164dd17f07e603c41fe1e506e641e57d18sewardj             && vex_control.guest_chase_cond
150170d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj             && (Addr32)d32 != (Addr32)guest_EIP_bbstart
15018984d9b164dd17f07e603c41fe1e506e641e57d18sewardj             && jmpDelta < 0
15019beac530a718fcc646bc61fe60a86f599df54e1d7florian             && resteerOkFn( callback_opaque, (Addr32)d32) ) {
15020984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            /* Speculation: assume this backward branch is taken.  So
15021984d9b164dd17f07e603c41fe1e506e641e57d18sewardj               we need to emit a side-exit to the insn following this
15022984d9b164dd17f07e603c41fe1e506e641e57d18sewardj               one, on the negation of the condition, and continue at
150230d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj               the branch target address (d32).  If we wind up back at
150240d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj               the first instruction of the trace, just stop; it's
150250d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj               better to let the IR loop unroller handle that case.*/
15026984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            stmt( IRStmt_Exit(
150270d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj                     mk_x86g_calculate_condition((X86Condcode)
150280d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj                                                 (1 ^ (opc - 0x80))),
15029984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                     Ijk_Boring,
15030c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     IRConst_U32(guest_EIP_bbstart+delta),
15031c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     OFFB_EIP ) );
15032984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            dres.whatNext   = Dis_ResteerC;
150330eaa35ff5569f09129073be27c2f827926f7010dflorian            dres.continueAt = (Addr32)d32;
15034984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            comment = "(assumed taken)";
15035984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         }
15036984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         else
15037984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         if (resteerCisOk
15038984d9b164dd17f07e603c41fe1e506e641e57d18sewardj             && vex_control.guest_chase_cond
150390d925b1ab27de28bf9f3ce468ae8ff23a507cd7asewardj             && (Addr32)d32 != (Addr32)guest_EIP_bbstart
15040984d9b164dd17f07e603c41fe1e506e641e57d18sewardj             && jmpDelta >= 0
15041984d9b164dd17f07e603c41fe1e506e641e57d18sewardj             && resteerOkFn( callback_opaque,
15042beac530a718fcc646bc61fe60a86f599df54e1d7florian                             (Addr32)(guest_EIP_bbstart+delta)) ) {
15043984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            /* Speculation: assume this forward branch is not taken.
15044984d9b164dd17f07e603c41fe1e506e641e57d18sewardj               So we need to emit a side-exit to d32 (the dest) and
15045984d9b164dd17f07e603c41fe1e506e641e57d18sewardj               continue disassembling at the insn immediately
15046984d9b164dd17f07e603c41fe1e506e641e57d18sewardj               following this one. */
15047984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            stmt( IRStmt_Exit(
15048984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                     mk_x86g_calculate_condition((X86Condcode)(opc - 0x80)),
15049984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                     Ijk_Boring,
15050c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     IRConst_U32(d32),
15051c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj                     OFFB_EIP ) );
15052984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            dres.whatNext   = Dis_ResteerC;
150530eaa35ff5569f09129073be27c2f827926f7010dflorian            dres.continueAt = guest_EIP_bbstart + delta;
15054984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            comment = "(assumed not taken)";
15055984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         }
15056984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         else {
15057984d9b164dd17f07e603c41fe1e506e641e57d18sewardj            /* Conservative default translation - end the block at
15058984d9b164dd17f07e603c41fe1e506e641e57d18sewardj               this point. */
15059c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            jcc_01( &dres, (X86Condcode)(opc - 0x80),
15060984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                    (Addr32)(guest_EIP_bbstart+delta), d32);
15061c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj            vassert(dres.whatNext == Dis_StopHere);
15062984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         }
15063984d9b164dd17f07e603c41fe1e506e641e57d18sewardj         DIP("j%s-32 0x%x %s\n", name_X86Condcode(opc - 0x80), d32, comment);
15064e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj         break;
15065984d9b164dd17f07e603c41fe1e506e641e57d18sewardj       }
15066e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
1506789cd09353a584000edaaa61558b27253bdea7452sewardj      /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
150684ed6429074bf94661586d751fbecac530f5e8156sewardj      case 0x31: { /* RDTSC */
150694ed6429074bf94661586d751fbecac530f5e8156sewardj         IRTemp   val  = newTemp(Ity_I64);
150704ed6429074bf94661586d751fbecac530f5e8156sewardj         IRExpr** args = mkIRExprVec_0();
150714ed6429074bf94661586d751fbecac530f5e8156sewardj         IRDirty* d    = unsafeIRDirty_1_N (
150724ed6429074bf94661586d751fbecac530f5e8156sewardj                            val,
150734ed6429074bf94661586d751fbecac530f5e8156sewardj                            0/*regparms*/,
150744ed6429074bf94661586d751fbecac530f5e8156sewardj                            "x86g_dirtyhelper_RDTSC",
150754ed6429074bf94661586d751fbecac530f5e8156sewardj                            &x86g_dirtyhelper_RDTSC,
150764ed6429074bf94661586d751fbecac530f5e8156sewardj                            args
150774ed6429074bf94661586d751fbecac530f5e8156sewardj                         );
15078a5cbbdc99afee50e9bcf1055fbc5b3e66dc1ecf3sewardj         /* execute the dirty call, dumping the result in val. */
15079a5cbbdc99afee50e9bcf1055fbc5b3e66dc1ecf3sewardj         stmt( IRStmt_Dirty(d) );
15080a5cbbdc99afee50e9bcf1055fbc5b3e66dc1ecf3sewardj         putIReg(4, R_EDX, unop(Iop_64HIto32, mkexpr(val)));
15081a5cbbdc99afee50e9bcf1055fbc5b3e66dc1ecf3sewardj         putIReg(4, R_EAX, unop(Iop_64to32, mkexpr(val)));
15082a5cbbdc99afee50e9bcf1055fbc5b3e66dc1ecf3sewardj         DIP("rdtsc\n");
15083a5cbbdc99afee50e9bcf1055fbc5b3e66dc1ecf3sewardj         break;
150844ed6429074bf94661586d751fbecac530f5e8156sewardj      }
1508577b86be374085943e902075b305ff047a053aac6sewardj
15086b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
15087b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
15088b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      case 0xA1: /* POP %FS */
15089b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj         dis_pop_segreg( R_FS, sz ); break;
15090b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      case 0xA9: /* POP %GS */
15091b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj         dis_pop_segreg( R_GS, sz ); break;
15092b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
15093b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      case 0xA0: /* PUSH %FS */
15094b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj         dis_push_segreg( R_FS, sz ); break;
15095b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      case 0xA8: /* PUSH %GS */
15096b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj         dis_push_segreg( R_GS, sz ); break;
15097b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj
1509877b86be374085943e902075b305ff047a053aac6sewardj      /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
1509977b86be374085943e902075b305ff047a053aac6sewardj      case 0x90:
1510077b86be374085943e902075b305ff047a053aac6sewardj      case 0x91:
1510177b86be374085943e902075b305ff047a053aac6sewardj      case 0x92: /* set-Bb/set-NAEb (jump below) */
1510277b86be374085943e902075b305ff047a053aac6sewardj      case 0x93: /* set-NBb/set-AEb (jump not below) */
1510377b86be374085943e902075b305ff047a053aac6sewardj      case 0x94: /* set-Zb/set-Eb (jump zero) */
1510477b86be374085943e902075b305ff047a053aac6sewardj      case 0x95: /* set-NZb/set-NEb (jump not zero) */
1510577b86be374085943e902075b305ff047a053aac6sewardj      case 0x96: /* set-BEb/set-NAb (jump below or equal) */
1510677b86be374085943e902075b305ff047a053aac6sewardj      case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
1510777b86be374085943e902075b305ff047a053aac6sewardj      case 0x98: /* set-Sb (jump negative) */
1510877b86be374085943e902075b305ff047a053aac6sewardj      case 0x99: /* set-Sb (jump not negative) */
1510977b86be374085943e902075b305ff047a053aac6sewardj      case 0x9A: /* set-P (jump parity even) */
1511077b86be374085943e902075b305ff047a053aac6sewardj      case 0x9B: /* set-NP (jump parity odd) */
1511177b86be374085943e902075b305ff047a053aac6sewardj      case 0x9C: /* set-Lb/set-NGEb (jump less) */
1511277b86be374085943e902075b305ff047a053aac6sewardj      case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
1511377b86be374085943e902075b305ff047a053aac6sewardj      case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
1511477b86be374085943e902075b305ff047a053aac6sewardj      case 0x9F: /* set-Gb/set-NLEb (jump greater) */
151155bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj         t1 = newTemp(Ity_I8);
151162a9ad023890d3b34cf45e429df2a8ae88b419128sewardj         assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
1511777b86be374085943e902075b305ff047a053aac6sewardj         modrm = getIByte(delta);
1511877b86be374085943e902075b305ff047a053aac6sewardj         if (epartIsReg(modrm)) {
1511977b86be374085943e902075b305ff047a053aac6sewardj            delta++;
151205bd4d1659f8f7f3eb44a719b1a368cf9ecb0a01esewardj            putIReg(1, eregOfRM(modrm), mkexpr(t1));
151212a9ad023890d3b34cf45e429df2a8ae88b419128sewardj            DIP("set%s %s\n", name_X86Condcode(opc-0x90),
1512277b86be374085943e902075b305ff047a053aac6sewardj                              nameIReg(1,eregOfRM(modrm)));
1512377b86be374085943e902075b305ff047a053aac6sewardj         } else {
15124750f407b6be1aac303964a219acf0a6de8b8c4dasewardj           addr = disAMode ( &alen, sorb, delta, dis_buf );
15125750f407b6be1aac303964a219acf0a6de8b8c4dasewardj           delta += alen;
15126750f407b6be1aac303964a219acf0a6de8b8c4dasewardj           storeLE( mkexpr(addr), mkexpr(t1) );
151272a9ad023890d3b34cf45e429df2a8ae88b419128sewardj           DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
1512877b86be374085943e902075b305ff047a053aac6sewardj         }
1512977b86be374085943e902075b305ff047a053aac6sewardj         break;
1513077b86be374085943e902075b305ff047a053aac6sewardj
15131180e8b39d5b4271e64634162986749c43536647csewardj      /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
15132180e8b39d5b4271e64634162986749c43536647csewardj
15133180e8b39d5b4271e64634162986749c43536647csewardj      case 0xA4: /* SHLDv imm8,Gv,Ev */
15134180e8b39d5b4271e64634162986749c43536647csewardj         modrm = getIByte(delta);
15135180e8b39d5b4271e64634162986749c43536647csewardj         d32   = delta + lengthAMode(delta);
151362d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj         vex_sprintf(dis_buf, "$%d", getIByte(d32));
15137180e8b39d5b4271e64634162986749c43536647csewardj         delta = dis_SHLRD_Gv_Ev (
15138180e8b39d5b4271e64634162986749c43536647csewardj                  sorb, delta, modrm, sz,
15139180e8b39d5b4271e64634162986749c43536647csewardj                  mkU8(getIByte(d32)), True, /* literal */
15140180e8b39d5b4271e64634162986749c43536647csewardj                  dis_buf, True );
15141180e8b39d5b4271e64634162986749c43536647csewardj         break;
15142a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj      case 0xA5: /* SHLDv %cl,Gv,Ev */
15143a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj         modrm = getIByte(delta);
15144a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj         delta = dis_SHLRD_Gv_Ev (
15145a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                    sorb, delta, modrm, sz,
15146a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                    getIReg(1,R_ECX), False, /* not literal */
15147a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj                    "%cl", True );
15148a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj         break;
15149a06e556d2c5fae9d19fbc3ea0e1aa54de2df90dbsewardj
1515068511549b138ef55c8d31088cb0f20a72d83ab2bsewardj      case 0xAC: /* SHRDv imm8,Gv,Ev */
1515168511549b138ef55c8d31088cb0f20a72d83ab2bsewardj         modrm = getIByte(delta);
1515268511549b138ef55c8d31088cb0f20a72d83ab2bsewardj         d32   = delta + lengthAMode(delta);
151532d49b43ae3dd3756ed6a6d7a66b54c7bd7e03af6sewardj         vex_sprintf(dis_buf, "$%d", getIByte(d32));
1515468511549b138ef55c8d31088cb0f20a72d83ab2bsewardj         delta = dis_SHLRD_Gv_Ev (
1515568511549b138ef55c8d31088cb0f20a72d83ab2bsewardj                    sorb, delta, modrm, sz,
1515668511549b138ef55c8d31088cb0f20a72d83ab2bsewardj                    mkU8(getIByte(d32)), True, /* literal */
1515768511549b138ef55c8d31088cb0f20a72d83ab2bsewardj                    dis_buf, False );
1515868511549b138ef55c8d31088cb0f20a72d83ab2bsewardj         break;
15159a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj      case 0xAD: /* SHRDv %cl,Gv,Ev */
15160a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj         modrm = getIByte(delta);
15161a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj         delta = dis_SHLRD_Gv_Ev (
15162a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj                    sorb, delta, modrm, sz,
15163a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj                    getIReg(1,R_ECX), False, /* not literal */
15164a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj                    "%cl", False );
15165a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj         break;
15166a511afc1c790d5fea951a42e0ab16f9bf81692d8sewardj
15167f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj      /* =-=-=-=-=-=-=-=-=- SYSENTER -=-=-=-=-=-=-=-=-=-= */
15168f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj
15169f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj      case 0x34:
15170f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj         /* Simple implementation needing a long explaination.
15171f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj
15172f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            sysenter is a kind of syscall entry.  The key thing here
15173f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            is that the return address is not known -- that is
15174f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            something that is beyond Vex's knowledge.  So this IR
15175f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            forces a return to the scheduler, which can do what it
151764fa325af3891d57d174a025af2e6e8810a553660sewardj            likes to simulate the systenter, but it MUST set this
15177f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            thread's guest_EIP field with the continuation address
15178f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            before resuming execution.  If that doesn't happen, the
15179f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            thread will jump to address zero, which is probably
15180f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj            fatal.
15181e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         */
15182e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj
15183e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         /* Note where we are, so we can back up the guest to this
15184e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj            point if the syscall needs to be restarted. */
15185e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
15186e86310f555a233cc2ca02e1a5d0adb555f12bdcdsewardj                           mkU32(guest_EIP_curr_instr) ) );
15187c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         jmp_lit(&dres, Ijk_Sys_sysenter, 0/*bogus next EIP value*/);
15188c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(dres.whatNext == Dis_StopHere);
15189f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj         DIP("sysenter");
15190f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj         break;
15191f07ed03a85d9929830a6df9f3d1a0545eedd231fsewardj
15192464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
15193464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
151940092e0d63a749778959b481a734dcbb3fb299766sewardj      case 0xC0: { /* XADD Gb,Eb */
151950092e0d63a749778959b481a734dcbb3fb299766sewardj         Bool decodeOK;
15196e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         delta = dis_xadd_G_E ( sorb, pfx_lock, 1, delta, &decodeOK );
151970092e0d63a749778959b481a734dcbb3fb299766sewardj         if (!decodeOK) goto decode_failure;
151980092e0d63a749778959b481a734dcbb3fb299766sewardj         break;
151990092e0d63a749778959b481a734dcbb3fb299766sewardj      }
152000092e0d63a749778959b481a734dcbb3fb299766sewardj      case 0xC1: { /* XADD Gv,Ev */
152010092e0d63a749778959b481a734dcbb3fb299766sewardj         Bool decodeOK;
15202e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         delta = dis_xadd_G_E ( sorb, pfx_lock, sz, delta, &decodeOK );
152030092e0d63a749778959b481a734dcbb3fb299766sewardj         if (!decodeOK) goto decode_failure;
15204883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj         break;
152050092e0d63a749778959b481a734dcbb3fb299766sewardj      }
15206883b00b3d97a9873371557d7b1f2ac5db7985e43sewardj
15207f13f37b9cc4219fa895526f34a5c2a45a8245cd3sewardj      /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
15208464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
152092b7a9208ee96939f12896085a143891160dc539asewardj      case 0x71:
152102b7a9208ee96939f12896085a143891160dc539asewardj      case 0x72:
1521138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
152122b7a9208ee96939f12896085a143891160dc539asewardj
152132b7a9208ee96939f12896085a143891160dc539asewardj      case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
152142b7a9208ee96939f12896085a143891160dc539asewardj      case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
15215464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
152162b7a9208ee96939f12896085a143891160dc539asewardj      case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
15217464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15218464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xFC:
15219464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xFD:
15220464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
15221464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15222464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xEC:
15223464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
15224464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15225464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xDC:
15226464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
15227464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15228464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xF8:
15229464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xF9:
15230464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
15231464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15232464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xE8:
15233464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
15234464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15235464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xD8:
15236464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
15237464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15238464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
15239464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
15240464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
152414340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
152424340dac5c2cede4962868e6da5b73282da2bc465sewardj
152434340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x74:
152444340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x75:
152454340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
152464340dac5c2cede4962868e6da5b73282da2bc465sewardj
152474340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x64:
152484340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x65:
152494340dac5c2cede4962868e6da5b73282da2bc465sewardj      case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
152504340dac5c2cede4962868e6da5b73282da2bc465sewardj
1525163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
1525263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
1525363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
1525463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
1525563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x68:
1525663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x69:
1525763ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
1525863ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
1525963ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x60:
1526063ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x61:
1526163ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
1526263ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
1526363ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
1526463ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
1526563ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
1526663ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj      case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
1526763ba4091e2d4b049f9a81d878cb3f3c97d6e20bfsewardj
1526838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
152698d14a59858e2464baa217f19daff83562f3cdca0sewardj      case 0xF2:
1527038a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xF3:
152718d14a59858e2464baa217f19daff83562f3cdca0sewardj
1527238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
152738d14a59858e2464baa217f19daff83562f3cdca0sewardj      case 0xD2:
1527438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xD3:
152758d14a59858e2464baa217f19daff83562f3cdca0sewardj
1527638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
1527738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj      case 0xE2:
15278464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      {
1527952d049186d07991237a825ec88aa7f1f303edb70sewardj         Int  delta0    = delta-1;
15280464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         Bool decode_OK = False;
1528138a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
1528238a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj         /* If sz==2 this is SSE, and we assume sse idec has
1528338a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj            already spotted those cases by now. */
1528438a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj         if (sz != 4)
1528538a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj            goto decode_failure;
1528638a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj
15287464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
15288464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         if (!decode_OK) {
15289464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            delta = delta0;
15290464efa446b2db97115d3e5f04af5db3464cc0e93sewardj            goto decode_failure;
15291464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         }
15292464efa446b2db97115d3e5f04af5db3464cc0e93sewardj         break;
15293464efa446b2db97115d3e5f04af5db3464cc0e93sewardj      }
15294464efa446b2db97115d3e5f04af5db3464cc0e93sewardj
15295e3aa0163ce611325d11bedcd5e69dc3ae1adebe7tom      case 0x0E: /* FEMMS */
152968d14a59858e2464baa217f19daff83562f3cdca0sewardj      case 0x77: /* EMMS */
1529738a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj         if (sz != 4)
1529838a3f868aebe4ade7279d7168e0efb6a98eaed5fsewardj            goto decode_failure;
152994cb918d355cef4e7640d374346852db4556f3524sewardj         do_EMMS_preamble();
15300e3aa0163ce611325d11bedcd5e69dc3ae1adebe7tom         DIP("{f}emms\n");
153018d14a59858e2464baa217f19daff83562f3cdca0sewardj         break;
153028d14a59858e2464baa217f19daff83562f3cdca0sewardj
15303b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj      /* =-=-=-=-=-=-=-=-=- SGDT and SIDT =-=-=-=-=-=-=-=-=-=-= */
15304b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj      case 0x01: /* 0F 01 /0 -- SGDT */
15305b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                 /* 0F 01 /1 -- SIDT */
15306b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj      {
15307b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj          /* This is really revolting, but ... since each processor
15308b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj             (core) only has one IDT and one GDT, just let the guest
15309b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj             see it (pass-through semantics).  I can't see any way to
15310b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj             construct a faked-up value, so don't bother to try. */
15311b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         modrm = getUChar(delta);
15312b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         addr = disAMode ( &alen, sorb, delta, dis_buf );
15313b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         delta += alen;
15314b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         if (epartIsReg(modrm)) goto decode_failure;
15315b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         if (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)
15316b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj            goto decode_failure;
15317b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         switch (gregOfRM(modrm)) {
15318b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj            case 0: DIP("sgdt %s\n", dis_buf); break;
15319b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj            case 1: DIP("sidt %s\n", dis_buf); break;
15320b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj            default: vassert(0); /*NOTREACHED*/
15321b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         }
15322b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj
15323b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         IRDirty* d = unsafeIRDirty_0_N (
15324b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                          0/*regparms*/,
15325b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                          "x86g_dirtyhelper_SxDT",
15326b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                          &x86g_dirtyhelper_SxDT,
15327b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                          mkIRExprVec_2( mkexpr(addr),
15328b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                                         mkU32(gregOfRM(modrm)) )
15329b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj                      );
15330b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         /* declare we're writing memory */
15331b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         d->mFx   = Ifx_Write;
15332b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         d->mAddr = mkexpr(addr);
15333b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         d->mSize = 6;
15334b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         stmt( IRStmt_Dirty(d) );
15335b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj         break;
15336b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj      }
15337b9dc2430577bddf8c42e3d3fbe887c32cada9130sewardj
15338f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom      case 0x05: /* AMD's syscall */
15339f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom         stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
15340f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom              mkU32(guest_EIP_curr_instr) ) );
15341f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom         jmp_lit(&dres, Ijk_Sys_syscall, ((Addr32)guest_EIP_bbstart)+delta);
15342f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom         vassert(dres.whatNext == Dis_StopHere);
15343f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom         DIP("syscall\n");
15344f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom         break;
15345f0bb67912ae5b4f5e08f20d28b2c49f279eec2d6tom
15346e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
15347e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj
15348e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj      default:
15349e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj         goto decode_failure;
15350e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   } /* switch (opc) for the 2-byte opcodes */
15351e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   goto decode_success;
15352e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj   } /* case 0x0F: of primary opcode */
15353c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
15354c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* ------------------------ ??? ------------------------ */
15355c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
15356c9a6570e86f4252f8a486b4df48de8710d357a4asewardj  default:
15357e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj  decode_failure:
15358c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* All decode failures end up here. */
15359442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj   if (sigill_diag) {
15360442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj      vex_printf("vex x86->IR: unhandled instruction bytes: "
15361442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj                 "0x%x 0x%x 0x%x 0x%x\n",
15362442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj                 (Int)getIByte(delta_start+0),
15363442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj                 (Int)getIByte(delta_start+1),
15364442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj                 (Int)getIByte(delta_start+2),
15365442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj                 (Int)getIByte(delta_start+3) );
15366442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj   }
1536752444cb6696efd612ced78daa8feb235808ef165sewardj
15368b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj   /* Tell the dispatcher that this insn cannot be decoded, and so has
15369b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      not been executed, and (is currently) the next to be executed.
15370b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      EIP should be up-to-date since it made so at the start of each
15371b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      insn, but nevertheless be paranoid and update it again right
15372b64821b9b132e7853b3e2f783b2ef57e19fd5c2asewardj      now. */
153739e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr) ) );
15374c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   jmp_lit(&dres, Ijk_NoDecode, guest_EIP_curr_instr);
15375c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   vassert(dres.whatNext == Dis_StopHere);
153769e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   dres.len = 0;
15377e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* We also need to say that a CAS is not expected now, regardless
15378e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      of what it might have been set to at the start of the function,
15379e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      since the IR that we've emitted just above (to synthesis a
15380e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      SIGILL) does not involve any CAS, and presumably no other IR has
15381e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      been emitted for this (non-decoded) insn. */
15382e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   *expect_CAS = False;
153839e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   return dres;
1538452444cb6696efd612ced78daa8feb235808ef165sewardj
15385c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   } /* switch (opc) for the main (primary) opcode switch. */
15386c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
15387e87b4840dc364d8203ccd3d6eeda348695cb4b8asewardj  decode_success:
15388c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   /* All decode successes end up here. */
15389c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   switch (dres.whatNext) {
15390c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      case Dis_Continue:
15391c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_bbstart + delta) ) );
15392c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         break;
15393c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      case Dis_ResteerU:
15394c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      case Dis_ResteerC:
15395c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         stmt( IRStmt_Put( OFFB_EIP, mkU32(dres.continueAt) ) );
15396c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         break;
15397c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      case Dis_StopHere:
15398c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         break;
15399c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      default:
15400c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj         vassert(0);
15401c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   }
15402c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj
15403c9a6570e86f4252f8a486b4df48de8710d357a4asewardj   DIP("\n");
154049e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   dres.len = delta - delta_start;
154059e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   return dres;
15406c9a6570e86f4252f8a486b4df48de8710d357a4asewardj}
15407c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
15408c9a6570e86f4252f8a486b4df48de8710d357a4asewardj#undef DIP
15409c9a6570e86f4252f8a486b4df48de8710d357a4asewardj#undef DIS
15410c9a6570e86f4252f8a486b4df48de8710d357a4asewardj
154119e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
154129e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj/*------------------------------------------------------------*/
154139e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj/*--- Top-level fn                                         ---*/
154149e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj/*------------------------------------------------------------*/
154159e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
154169e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj/* Disassemble a single instruction into IR.  The instruction
154179e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   is located in host memory at &guest_code[delta]. */
154189e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
15419dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardjDisResult disInstr_X86 ( IRSB*        irsb_IN,
15420beac530a718fcc646bc61fe60a86f599df54e1d7florian                         Bool         (*resteerOkFn) ( void*, Addr ),
15421984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                         Bool         resteerCisOk,
15422c716aea1cafe66ee431dc7d6909c98f18788a028sewardj                         void*        callback_opaque,
154238462d113e3efeacceb304222dada8d85f748295aflorian                         const UChar* guest_code_IN,
154249e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj                         Long         delta,
15425d4cc0deec55ec0be1f2ac3b20f0d340265341f83florian                         Addr         guest_IP,
15426a5f55da7e956978fddad927436da5fab9568f3f1sewardj                         VexArch      guest_arch,
15427cacba8e675988fbf21b08feea1f317a9c896c053florian                         const VexArchInfo* archinfo,
15428cacba8e675988fbf21b08feea1f317a9c896c053florian                         const VexAbiInfo*  abiinfo,
154299b76916dcc1628e133d57db001563429c6e3a590sewardj                         VexEndness   host_endness_IN,
15430442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj                         Bool         sigill_diag_IN )
154319e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj{
15432e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   Int       i, x1, x2;
15433e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   Bool      expect_CAS, has_CAS;
154349e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   DisResult dres;
154359e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
154369e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   /* Set globals (see top of this file) */
15437a5f55da7e956978fddad927436da5fab9568f3f1sewardj   vassert(guest_arch == VexArchX86);
154389e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   guest_code           = guest_code_IN;
15439dd40fdf58cc8a6fe9466c4f00bdfc9fe9bf00449sewardj   irsb                 = irsb_IN;
154409b76916dcc1628e133d57db001563429c6e3a590sewardj   host_endness         = host_endness_IN;
154419e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   guest_EIP_curr_instr = (Addr32)guest_IP;
154429e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   guest_EIP_bbstart    = (Addr32)toUInt(guest_IP - delta);
154439e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
15444e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   x1 = irsb_IN->stmts_used;
15445e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   expect_CAS = False;
15446c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj   dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
15447984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                             resteerCisOk,
154480283430ee809d645864ddd2da5f450f88142b4cdsewardj                             callback_opaque,
15449442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj                             delta, archinfo, abiinfo, sigill_diag_IN );
15450e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   x2 = irsb_IN->stmts_used;
15451e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   vassert(x2 >= x1);
15452e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
15453e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   /* See comment at the top of disInstr_X86_WRK for meaning of
15454e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      expect_CAS.  Here, we (sanity-)check for the presence/absence of
15455e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      IRCAS as directed by the returned expect_CAS value. */
15456e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   has_CAS = False;
15457e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   for (i = x1; i < x2; i++) {
15458e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      if (irsb_IN->stmts[i]->tag == Ist_CAS)
15459e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         has_CAS = True;
15460e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
15461e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj
15462e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   if (expect_CAS != has_CAS) {
15463e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* inconsistency detected.  re-disassemble the instruction so as
15464e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         to generate a useful error message; then assert. */
15465e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      vex_traceflags |= VEX_TRACE_FE;
15466c6f970f1fadb640d69c78ac2669efab5c08f1e8dsewardj      dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
15467984d9b164dd17f07e603c41fe1e506e641e57d18sewardj                                resteerCisOk,
154680283430ee809d645864ddd2da5f450f88142b4cdsewardj                                callback_opaque,
15469442e51a26cf3bc7f243167a4ff3fbfb02206f6e6sewardj                                delta, archinfo, abiinfo, sigill_diag_IN );
15470e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      for (i = x1; i < x2; i++) {
15471e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         vex_printf("\t\t");
15472e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         ppIRStmt(irsb_IN->stmts[i]);
15473e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         vex_printf("\n");
15474e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      }
15475e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      /* Failure of this assertion is serious and denotes a bug in
15476e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj         disInstr. */
15477e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj      vpanic("disInstr_X86: inconsistency in LOCK prefix handling");
15478e9d8a26b690c2561ac54ab0cd6ad83ecbadcbe76sewardj   }
154799e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
154809e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj   return dres;
154819e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj}
154829e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
154839e6491ab55324b8e45e187b1e1e9632ac3cb3e27sewardj
15484c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*--------------------------------------------------------------------*/
15485cef7d3e3df4796e35b4521158d9dc058f034aa87sewardj/*--- end                                         guest_x86_toIR.c ---*/
15486c9a6570e86f4252f8a486b4df48de8710d357a4asewardj/*--------------------------------------------------------------------*/
15487