blob: 2bf234a772d12834a33519465f73c84081586afa [file] [log] [blame]
sewardjc9a65702004-07-07 16:32:57 +00001
2/*--------------------------------------------------------------------*/
sewardj752f9062010-05-03 21:38:49 +00003/*--- begin guest_x86_toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +00004/*--------------------------------------------------------------------*/
5
sewardjf8ed9d82004-11-12 17:40:23 +00006/*
sewardj752f9062010-05-03 21:38:49 +00007 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
sewardjf8ed9d82004-11-12 17:40:23 +00009
sewardj752f9062010-05-03 21:38:49 +000010 Copyright (C) 2004-2010 OpenWorks LLP
11 info@open-works.net
sewardjf8ed9d82004-11-12 17:40:23 +000012
sewardj752f9062010-05-03 21:38:49 +000013 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
sewardjf8ed9d82004-11-12 17:40:23 +000017
sewardj752f9062010-05-03 21:38:49 +000018 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
sewardj7bd6ffe2005-08-03 16:07:36 +000026 02110-1301, USA.
27
sewardj752f9062010-05-03 21:38:49 +000028 The GNU General Public License is contained in the file COPYING.
sewardjf8ed9d82004-11-12 17:40:23 +000029
30 Neither the names of the U.S. Department of Energy nor the
31 University of California nor the names of its contributors may be
32 used to endorse or promote products derived from this software
33 without prior written permission.
sewardjf8ed9d82004-11-12 17:40:23 +000034*/
35
sewardje9d8a262009-07-01 08:06:34 +000036/* Translates x86 code to IR. */
37
sewardj77b86be2004-07-11 13:28:24 +000038/* TODO:
sewardj45f1ff82005-05-05 12:04:14 +000039
sewardj3b3eacd2005-08-24 10:01:36 +000040 All Puts to CC_OP/CC_DEP1/CC_DEP2/CC_NDEP should really be checked
41 to ensure a 32-bit value is being written.
42
sewardj883b00b2004-09-11 09:30:24 +000043 FUCOMI(P): what happens to A and S flags? Currently are forced
44 to zero.
sewardj3f61ddb2004-10-16 20:51:05 +000045
sewardjce70a5c2004-10-18 14:09:54 +000046 x87 FP Limitations:
sewardja0e83b02005-01-06 12:36:38 +000047
48 * all arithmetic done at 64 bits
49
sewardj3f61ddb2004-10-16 20:51:05 +000050 * no FP exceptions, except for handling stack over/underflow
sewardja0e83b02005-01-06 12:36:38 +000051
sewardj3f61ddb2004-10-16 20:51:05 +000052 * FP rounding mode observed only for float->int conversions
sewardja0e83b02005-01-06 12:36:38 +000053 and int->float conversions which could lose accuracy, and
54 for float-to-float rounding. For all other operations,
55 round-to-nearest is used, regardless.
56
sewardj3f61ddb2004-10-16 20:51:05 +000057 * FP sin/cos/tan/sincos: C2 flag is always cleared. IOW the
58 simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
59 even when it isn't.
sewardja0e83b02005-01-06 12:36:38 +000060
sewardje166ed02004-10-25 02:27:01 +000061 * some of the FCOM cases could do with testing -- not convinced
62 that the args are the right way round.
sewardj52444cb2004-12-13 14:09:01 +000063
sewardja0e83b02005-01-06 12:36:38 +000064 * FSAVE does not re-initialise the FPU; it should do
65
66 * FINIT not only initialises the FPU environment, it also
67 zeroes all the FP registers. It should leave the registers
68 unchanged.
69
sewardjcb2c99d2004-12-17 19:14:24 +000070 SAHF should cause eflags[1] == 1, and in fact it produces 0. As
71 per Intel docs this bit has no meaning anyway. Since PUSHF is the
72 only way to observe eflags[1], a proper fix would be to make that
73 bit be set by PUSHF.
74
sewardj6d269842005-08-06 11:45:02 +000075 The state of %eflags.AC (alignment check, bit 18) is recorded by
76 the simulation (viz, if you set it with popf then a pushf produces
77 the value you set it to), but it is otherwise ignored. In
78 particular, setting it to 1 does NOT cause alignment checking to
79 happen. Programs that set it to 1 and then rely on the resulting
80 SIGBUSs to inform them of misaligned accesses will not work.
81
sewardje9d8a262009-07-01 08:06:34 +000082 Implementation of sysenter is necessarily partial. sysenter is a
83 kind of system call entry. When doing a sysenter, the return
84 address is not known -- that is something that is beyond Vex's
85 knowledge. So the generated IR forces a return to the scheduler,
86 which can do what it likes to simulate the systenter, but it MUST
87 set this thread's guest_EIP field with the continuation address
88 before resuming execution. If that doesn't happen, the thread will
89 jump to address zero, which is probably fatal.
sewardjf07ed032005-08-07 14:48:03 +000090
sewardj52444cb2004-12-13 14:09:01 +000091 This module uses global variables and so is not MT-safe (if that
sewardje395ae82005-02-26 02:00:50 +000092 should ever become relevant).
93
94 The delta values are 32-bit ints, not 64-bit ints. That means
95 this module may not work right if run on a 64-bit host. That should
96 be fixed properly, really -- if anyone ever wants to use Vex to
sewardje9d8a262009-07-01 08:06:34 +000097 translate x86 code for execution on a 64-bit host.
98
99 casLE (implementation of lock-prefixed insns) and rep-prefixed
100 insns: the side-exit back to the start of the insn is done with
101 Ijk_Boring. This is quite wrong, it should be done with
102 Ijk_NoRedir, since otherwise the side exit, which is intended to
103 restart the instruction for whatever reason, could go somewhere
104 entirely else. Doing it right (with Ijk_NoRedir jumps) would make
105 no-redir jumps performance critical, at least for rep-prefixed
106 instructions, since all iterations thereof would involve such a
107 jump. It's not such a big deal with casLE since the side exit is
108 only taken if the CAS fails, that is, the location is contended,
109 which is relatively unlikely.
sewardj1fb8c922009-07-12 12:56:53 +0000110
sewardj6c299f32009-12-31 18:00:12 +0000111 XXXX: Nov 2009: handling of SWP on ARM suffers from the same
112 problem.
113
sewardj1fb8c922009-07-12 12:56:53 +0000114 Note also, the test for CAS success vs failure is done using
115 Iop_CasCmp{EQ,NE}{8,16,32,64} rather than the ordinary
116 Iop_Cmp{EQ,NE} equivalents. This is so as to tell Memcheck that it
117 shouldn't definedness-check these comparisons. See
118 COMMENT_ON_CasCmpEQ in memcheck/mc_translate.c for
119 background/rationale.
sewardje9d8a262009-07-01 08:06:34 +0000120*/
sewardje05c42c2004-07-08 20:25:10 +0000121
sewardj9f8a3952005-04-06 10:27:11 +0000122/* Performance holes:
123
124 - fcom ; fstsw %ax ; sahf
125 sahf does not update the O flag (sigh) and so O needs to
126 be computed. This is done expensively; it would be better
127 to have a calculate_eflags_o helper.
128
129 - emwarns; some FP codes can generate huge numbers of these
130 if the fpucw is changed in an inner loop. It would be
131 better for the guest state to have an emwarn-enable reg
132 which can be set zero or nonzero. If it is zero, emwarns
133 are not flagged, and instead control just flows all the
134 way through bbs as usual.
135*/
136
sewardjce02aa72006-01-12 12:27:58 +0000137/* "Special" instructions.
138
139 This instruction decoder can decode three special instructions
140 which mean nothing natively (are no-ops as far as regs/mem are
141 concerned) but have meaning for supporting Valgrind. A special
142 instruction is flagged by the 12-byte preamble C1C703 C1C70D C1C71D
143 C1C713 (in the standard interpretation, that means: roll $3, %edi;
144 roll $13, %edi; roll $29, %edi; roll $19, %edi). Following that,
145 one of the following 3 are allowed (standard interpretation in
146 parentheses):
147
148 87DB (xchgl %ebx,%ebx) %EDX = client_request ( %EAX )
149 87C9 (xchgl %ecx,%ecx) %EAX = guest_NRADDR
150 87D2 (xchgl %edx,%edx) call-noredir *%EAX
151
152 Any other bytes following the 12-byte preamble are illegal and
153 constitute a failure in instruction decoding. This all assumes
154 that the preamble will never occur except in specific code
155 fragments designed for Valgrind to catch.
156
157 No prefixes may precede a "Special" instruction.
158*/
159
sewardje9d8a262009-07-01 08:06:34 +0000160/* LOCK prefixed instructions. These are translated using IR-level
161 CAS statements (IRCAS) and are believed to preserve atomicity, even
162 from the point of view of some other process racing against a
163 simulated one (presumably they communicate via a shared memory
164 segment).
sewardjce02aa72006-01-12 12:27:58 +0000165
sewardje9d8a262009-07-01 08:06:34 +0000166 Handlers which are aware of LOCK prefixes are:
167 dis_op2_G_E (add, or, adc, sbb, and, sub, xor)
168 dis_cmpxchg_G_E (cmpxchg)
169 dis_Grp1 (add, or, adc, sbb, and, sub, xor)
170 dis_Grp3 (not, neg)
171 dis_Grp4 (inc, dec)
172 dis_Grp5 (inc, dec)
173 dis_Grp8_Imm (bts, btc, btr)
174 dis_bt_G_E (bts, btc, btr)
175 dis_xadd_G_E (xadd)
176*/
177
sewardjc9a65702004-07-07 16:32:57 +0000178
179#include "libvex_basictypes.h"
180#include "libvex_ir.h"
sewardje87b4842004-07-10 12:23:30 +0000181#include "libvex.h"
sewardjf6dc3ce2004-10-19 01:03:46 +0000182#include "libvex_guest_x86.h"
sewardjc0ee2ed2004-07-27 10:29:41 +0000183
sewardjcef7d3e2009-07-02 12:21:59 +0000184#include "main_util.h"
185#include "main_globals.h"
186#include "guest_generic_bb_to_IR.h"
187#include "guest_generic_x87.h"
188#include "guest_x86_defs.h"
sewardjc9a65702004-07-07 16:32:57 +0000189
190
191/*------------------------------------------------------------*/
192/*--- Globals ---*/
193/*------------------------------------------------------------*/
194
sewardj9e6491a2005-07-02 19:24:10 +0000195/* These are set at the start of the translation of an insn, right
196 down in disInstr_X86, so that we don't have to pass them around
197 endlessly. They are all constant during the translation of any
198 given insn. */
sewardjc9a65702004-07-07 16:32:57 +0000199
200/* We need to know this to do sub-register accesses correctly. */
sewardjc9a65702004-07-07 16:32:57 +0000201static Bool host_is_bigendian;
202
sewardj9e6491a2005-07-02 19:24:10 +0000203/* Pointer to the guest code area (points to start of BB, not to the
204 insn being processed). */
sewardjc9a65702004-07-07 16:32:57 +0000205static UChar* guest_code;
206
207/* The guest address corresponding to guest_code[0]. */
sewardj9e6491a2005-07-02 19:24:10 +0000208static Addr32 guest_EIP_bbstart;
sewardjc9a65702004-07-07 16:32:57 +0000209
sewardj52444cb2004-12-13 14:09:01 +0000210/* The guest address for the instruction currently being
211 translated. */
sewardj9e6491a2005-07-02 19:24:10 +0000212static Addr32 guest_EIP_curr_instr;
sewardj52444cb2004-12-13 14:09:01 +0000213
sewardjdd40fdf2006-12-24 02:20:24 +0000214/* The IRSB* into which we're generating code. */
215static IRSB* irsb;
sewardjc9a65702004-07-07 16:32:57 +0000216
sewardjc9a65702004-07-07 16:32:57 +0000217
sewardjce70a5c2004-10-18 14:09:54 +0000218/*------------------------------------------------------------*/
219/*--- Debugging output ---*/
220/*------------------------------------------------------------*/
221
sewardjf48ac192004-10-29 00:41:29 +0000222#define DIP(format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000223 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +0000224 vex_printf(format, ## args)
225
sewardjf48ac192004-10-29 00:41:29 +0000226#define DIS(buf, format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000227 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +0000228 vex_sprintf(buf, format, ## args)
229
230
231/*------------------------------------------------------------*/
sewardjdcc85fc2004-10-26 13:26:20 +0000232/*--- Offsets of various parts of the x86 guest state. ---*/
233/*------------------------------------------------------------*/
234
sewardjc9a43662004-11-30 18:51:59 +0000235#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
236#define OFFB_EBX offsetof(VexGuestX86State,guest_EBX)
237#define OFFB_ECX offsetof(VexGuestX86State,guest_ECX)
238#define OFFB_EDX offsetof(VexGuestX86State,guest_EDX)
239#define OFFB_ESP offsetof(VexGuestX86State,guest_ESP)
240#define OFFB_EBP offsetof(VexGuestX86State,guest_EBP)
241#define OFFB_ESI offsetof(VexGuestX86State,guest_ESI)
242#define OFFB_EDI offsetof(VexGuestX86State,guest_EDI)
sewardj2a2ba8b2004-11-08 13:14:06 +0000243
sewardjc9a43662004-11-30 18:51:59 +0000244#define OFFB_EIP offsetof(VexGuestX86State,guest_EIP)
sewardj2a2ba8b2004-11-08 13:14:06 +0000245
sewardjc9a43662004-11-30 18:51:59 +0000246#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
247#define OFFB_CC_DEP1 offsetof(VexGuestX86State,guest_CC_DEP1)
248#define OFFB_CC_DEP2 offsetof(VexGuestX86State,guest_CC_DEP2)
249#define OFFB_CC_NDEP offsetof(VexGuestX86State,guest_CC_NDEP)
sewardj893aada2004-11-29 19:57:54 +0000250
sewardjc9a43662004-11-30 18:51:59 +0000251#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
252#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
253#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
254#define OFFB_IDFLAG offsetof(VexGuestX86State,guest_IDFLAG)
sewardj6d269842005-08-06 11:45:02 +0000255#define OFFB_ACFLAG offsetof(VexGuestX86State,guest_ACFLAG)
sewardjc9a43662004-11-30 18:51:59 +0000256#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
257#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
258#define OFFB_FPROUND offsetof(VexGuestX86State,guest_FPROUND)
259
260#define OFFB_CS offsetof(VexGuestX86State,guest_CS)
261#define OFFB_DS offsetof(VexGuestX86State,guest_DS)
262#define OFFB_ES offsetof(VexGuestX86State,guest_ES)
263#define OFFB_FS offsetof(VexGuestX86State,guest_FS)
264#define OFFB_GS offsetof(VexGuestX86State,guest_GS)
265#define OFFB_SS offsetof(VexGuestX86State,guest_SS)
sewardj3bd6f3e2004-12-13 10:48:19 +0000266#define OFFB_LDT offsetof(VexGuestX86State,guest_LDT)
267#define OFFB_GDT offsetof(VexGuestX86State,guest_GDT)
sewardjc9a43662004-11-30 18:51:59 +0000268
269#define OFFB_SSEROUND offsetof(VexGuestX86State,guest_SSEROUND)
270#define OFFB_XMM0 offsetof(VexGuestX86State,guest_XMM0)
271#define OFFB_XMM1 offsetof(VexGuestX86State,guest_XMM1)
272#define OFFB_XMM2 offsetof(VexGuestX86State,guest_XMM2)
273#define OFFB_XMM3 offsetof(VexGuestX86State,guest_XMM3)
274#define OFFB_XMM4 offsetof(VexGuestX86State,guest_XMM4)
275#define OFFB_XMM5 offsetof(VexGuestX86State,guest_XMM5)
276#define OFFB_XMM6 offsetof(VexGuestX86State,guest_XMM6)
277#define OFFB_XMM7 offsetof(VexGuestX86State,guest_XMM7)
278
279#define OFFB_EMWARN offsetof(VexGuestX86State,guest_EMWARN)
sewardjdcc85fc2004-10-26 13:26:20 +0000280
sewardjbfceb082005-11-15 11:16:30 +0000281#define OFFB_TISTART offsetof(VexGuestX86State,guest_TISTART)
282#define OFFB_TILEN offsetof(VexGuestX86State,guest_TILEN)
sewardjce02aa72006-01-12 12:27:58 +0000283#define OFFB_NRADDR offsetof(VexGuestX86State,guest_NRADDR)
284
sewardje86310f2009-03-19 22:21:40 +0000285#define OFFB_IP_AT_SYSCALL offsetof(VexGuestX86State,guest_IP_AT_SYSCALL)
286
sewardjdcc85fc2004-10-26 13:26:20 +0000287
288/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +0000289/*--- Helper bits and pieces for deconstructing the ---*/
290/*--- x86 insn stream. ---*/
291/*------------------------------------------------------------*/
292
293/* This is the Intel register encoding -- integer regs. */
294#define R_EAX 0
295#define R_ECX 1
296#define R_EDX 2
297#define R_EBX 3
298#define R_ESP 4
299#define R_EBP 5
300#define R_ESI 6
301#define R_EDI 7
302
303#define R_AL (0+R_EAX)
304#define R_AH (4+R_EAX)
305
sewardj063f02f2004-10-20 12:36:12 +0000306/* This is the Intel register encoding -- segment regs. */
307#define R_ES 0
308#define R_CS 1
309#define R_SS 2
310#define R_DS 3
311#define R_FS 4
312#define R_GS 5
313
sewardjce70a5c2004-10-18 14:09:54 +0000314
sewardjc9a65702004-07-07 16:32:57 +0000315/* Add a statement to the list held by "irbb". */
sewardjd7cb8532004-08-17 23:59:23 +0000316static void stmt ( IRStmt* st )
sewardjc9a65702004-07-07 16:32:57 +0000317{
sewardjdd40fdf2006-12-24 02:20:24 +0000318 addStmtToIRSB( irsb, st );
sewardjc9a65702004-07-07 16:32:57 +0000319}
320
321/* Generate a new temporary of the given type. */
322static IRTemp newTemp ( IRType ty )
323{
sewardj496a58d2005-03-20 18:44:44 +0000324 vassert(isPlausibleIRType(ty));
sewardjdd40fdf2006-12-24 02:20:24 +0000325 return newIRTemp( irsb->tyenv, ty );
sewardjc9a65702004-07-07 16:32:57 +0000326}
327
sewardjce70a5c2004-10-18 14:09:54 +0000328/* Various simple conversions */
sewardjd1061ab2004-07-08 01:45:30 +0000329
sewardje05c42c2004-07-08 20:25:10 +0000330static UInt extend_s_8to32( UInt x )
sewardjd1061ab2004-07-08 01:45:30 +0000331{
332 return (UInt)((((Int)x) << 24) >> 24);
333}
334
sewardj0611d802004-07-11 02:37:54 +0000335static UInt extend_s_16to32 ( UInt x )
336{
337 return (UInt)((((Int)x) << 16) >> 16);
338}
339
sewardjd1061ab2004-07-08 01:45:30 +0000340/* Fetch a byte from the guest insn stream. */
sewardj52d04912005-07-03 00:52:48 +0000341static UChar getIByte ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000342{
343 return guest_code[delta];
344}
345
sewardjc9a65702004-07-07 16:32:57 +0000346/* Extract the reg field from a modRM byte. */
sewardje05c42c2004-07-08 20:25:10 +0000347static Int gregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000348{
349 return (Int)( (mod_reg_rm >> 3) & 7 );
350}
351
352/* Figure out whether the mod and rm parts of a modRM byte refer to a
353 register or memory. If so, the byte will have the form 11XXXYYY,
354 where YYY is the register number. */
sewardje05c42c2004-07-08 20:25:10 +0000355static Bool epartIsReg ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000356{
sewardj2d49b432005-02-01 00:37:06 +0000357 return toBool(0xC0 == (mod_reg_rm & 0xC0));
sewardjc9a65702004-07-07 16:32:57 +0000358}
359
360/* ... and extract the register number ... */
sewardje05c42c2004-07-08 20:25:10 +0000361static Int eregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000362{
363 return (Int)(mod_reg_rm & 0x7);
364}
365
sewardje05c42c2004-07-08 20:25:10 +0000366/* Get a 8/16/32-bit unsigned value out of the insn stream. */
367
sewardj52d04912005-07-03 00:52:48 +0000368static UChar getUChar ( Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000369{
sewardj2d49b432005-02-01 00:37:06 +0000370 UChar v = guest_code[delta+0];
sewardj9b45b482005-02-07 01:42:18 +0000371 return toUChar(v);
sewardje05c42c2004-07-08 20:25:10 +0000372}
373
sewardj52d04912005-07-03 00:52:48 +0000374static UInt getUDisp16 ( Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000375{
376 UInt v = guest_code[delta+1]; v <<= 8;
377 v |= guest_code[delta+0];
378 return v & 0xFFFF;
379}
380
sewardj52d04912005-07-03 00:52:48 +0000381static UInt getUDisp32 ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000382{
383 UInt v = guest_code[delta+3]; v <<= 8;
384 v |= guest_code[delta+2]; v <<= 8;
385 v |= guest_code[delta+1]; v <<= 8;
386 v |= guest_code[delta+0];
387 return v;
388}
389
sewardj52d04912005-07-03 00:52:48 +0000390static UInt getUDisp ( Int size, Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000391{
392 switch (size) {
393 case 4: return getUDisp32(delta);
394 case 2: return getUDisp16(delta);
sewardj2d49b432005-02-01 00:37:06 +0000395 case 1: return (UInt)getUChar(delta);
sewardje05c42c2004-07-08 20:25:10 +0000396 default: vpanic("getUDisp(x86)");
397 }
398 return 0; /*notreached*/
399}
400
401
sewardjd1061ab2004-07-08 01:45:30 +0000402/* Get a byte value out of the insn stream and sign-extend to 32
403 bits. */
sewardj52d04912005-07-03 00:52:48 +0000404static UInt getSDisp8 ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000405{
406 return extend_s_8to32( (UInt) (guest_code[delta]) );
407}
408
sewardj52d04912005-07-03 00:52:48 +0000409static UInt getSDisp16 ( Int delta0 )
sewardj0611d802004-07-11 02:37:54 +0000410{
411 UChar* eip = (UChar*)(&guest_code[delta0]);
412 UInt d = *eip++;
413 d |= ((*eip++) << 8);
414 return extend_s_16to32(d);
415}
416
sewardj52d04912005-07-03 00:52:48 +0000417static UInt getSDisp ( Int size, Int delta )
sewardj0611d802004-07-11 02:37:54 +0000418{
419 switch (size) {
420 case 4: return getUDisp32(delta);
421 case 2: return getSDisp16(delta);
422 case 1: return getSDisp8(delta);
423 default: vpanic("getSDisp(x86)");
424 }
425 return 0; /*notreached*/
426}
sewardjd1061ab2004-07-08 01:45:30 +0000427
sewardjc9a65702004-07-07 16:32:57 +0000428
429/*------------------------------------------------------------*/
430/*--- Helpers for constructing IR. ---*/
431/*------------------------------------------------------------*/
432
433/* Create a 1/2/4 byte read of an x86 integer registers. For 16/8 bit
434 register references, we need to take the host endianness into
435 account. Supplied value is 0 .. 7 and in the Intel instruction
436 encoding. */
sewardje05c42c2004-07-08 20:25:10 +0000437
sewardj9334b0f2004-07-10 22:43:54 +0000438static IRType szToITy ( Int n )
439{
440 switch (n) {
441 case 1: return Ity_I8;
442 case 2: return Ity_I16;
443 case 4: return Ity_I32;
444 default: vpanic("szToITy(x86)");
445 }
446}
447
sewardj67e002d2004-12-02 18:16:33 +0000448/* On a little-endian host, less significant bits of the guest
449 registers are at lower addresses. Therefore, if a reference to a
450 register low half has the safe guest state offset as a reference to
451 the full register.
452*/
sewardj9334b0f2004-07-10 22:43:54 +0000453static Int integerGuestRegOffset ( Int sz, UInt archreg )
454{
455 vassert(archreg < 8);
456
sewardj9334b0f2004-07-10 22:43:54 +0000457 /* Correct for little-endian host only. */
sewardj67e002d2004-12-02 18:16:33 +0000458 vassert(!host_is_bigendian);
sewardj063f02f2004-10-20 12:36:12 +0000459
460 if (sz == 4 || sz == 2 || (sz == 1 && archreg < 4)) {
461 switch (archreg) {
sewardjc9a43662004-11-30 18:51:59 +0000462 case R_EAX: return OFFB_EAX;
463 case R_EBX: return OFFB_EBX;
464 case R_ECX: return OFFB_ECX;
465 case R_EDX: return OFFB_EDX;
466 case R_ESI: return OFFB_ESI;
467 case R_EDI: return OFFB_EDI;
468 case R_ESP: return OFFB_ESP;
469 case R_EBP: return OFFB_EBP;
sewardj063f02f2004-10-20 12:36:12 +0000470 default: vpanic("integerGuestRegOffset(x86,le)(4,2)");
471 }
472 }
473
474 vassert(archreg >= 4 && archreg < 8 && sz == 1);
475 switch (archreg-4) {
sewardjc9a43662004-11-30 18:51:59 +0000476 case R_EAX: return 1+ OFFB_EAX;
477 case R_EBX: return 1+ OFFB_EBX;
478 case R_ECX: return 1+ OFFB_ECX;
479 case R_EDX: return 1+ OFFB_EDX;
sewardj063f02f2004-10-20 12:36:12 +0000480 default: vpanic("integerGuestRegOffset(x86,le)(1h)");
481 }
482
483 /* NOTREACHED */
484 vpanic("integerGuestRegOffset(x86,le)");
485}
486
487static Int segmentGuestRegOffset ( UInt sreg )
488{
489 switch (sreg) {
sewardjc9a43662004-11-30 18:51:59 +0000490 case R_ES: return OFFB_ES;
491 case R_CS: return OFFB_CS;
492 case R_SS: return OFFB_SS;
493 case R_DS: return OFFB_DS;
494 case R_FS: return OFFB_FS;
495 case R_GS: return OFFB_GS;
sewardj063f02f2004-10-20 12:36:12 +0000496 default: vpanic("segmentGuestRegOffset(x86)");
sewardj9334b0f2004-07-10 22:43:54 +0000497 }
498}
499
sewardjc9a43662004-11-30 18:51:59 +0000500static Int xmmGuestRegOffset ( UInt xmmreg )
501{
502 switch (xmmreg) {
503 case 0: return OFFB_XMM0;
504 case 1: return OFFB_XMM1;
505 case 2: return OFFB_XMM2;
506 case 3: return OFFB_XMM3;
507 case 4: return OFFB_XMM4;
508 case 5: return OFFB_XMM5;
509 case 6: return OFFB_XMM6;
510 case 7: return OFFB_XMM7;
511 default: vpanic("xmmGuestRegOffset");
512 }
513}
514
sewardj67e002d2004-12-02 18:16:33 +0000515/* Lanes of vector registers are always numbered from zero being the
516 least significant lane (rightmost in the register). */
517
sewardje5854d62004-12-09 03:44:34 +0000518static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
519{
520 /* Correct for little-endian host only. */
521 vassert(!host_is_bigendian);
522 vassert(laneno >= 0 && laneno < 8);
523 return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
524}
525
sewardj67e002d2004-12-02 18:16:33 +0000526static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
527{
528 /* Correct for little-endian host only. */
529 vassert(!host_is_bigendian);
530 vassert(laneno >= 0 && laneno < 4);
531 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
532}
533
534static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
535{
536 /* Correct for little-endian host only. */
537 vassert(!host_is_bigendian);
538 vassert(laneno >= 0 && laneno < 2);
539 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
540}
541
sewardjd1061ab2004-07-08 01:45:30 +0000542static IRExpr* getIReg ( Int sz, UInt archreg )
sewardjc9a65702004-07-07 16:32:57 +0000543{
544 vassert(sz == 1 || sz == 2 || sz == 4);
545 vassert(archreg < 8);
sewardj9334b0f2004-07-10 22:43:54 +0000546 return IRExpr_Get( integerGuestRegOffset(sz,archreg),
sewardj5bd4d162004-11-10 13:02:48 +0000547 szToITy(sz) );
sewardjc9a65702004-07-07 16:32:57 +0000548}
549
550/* Ditto, but write to a reg instead. */
sewardj41f43bc2004-07-08 14:23:22 +0000551static void putIReg ( Int sz, UInt archreg, IRExpr* e )
sewardjc9a65702004-07-07 16:32:57 +0000552{
sewardjdd40fdf2006-12-24 02:20:24 +0000553 IRType ty = typeOfIRExpr(irsb->tyenv, e);
sewardjd24931d2005-03-20 12:51:39 +0000554 switch (sz) {
555 case 1: vassert(ty == Ity_I8); break;
556 case 2: vassert(ty == Ity_I16); break;
557 case 4: vassert(ty == Ity_I32); break;
558 default: vpanic("putIReg(x86)");
559 }
sewardjc9a65702004-07-07 16:32:57 +0000560 vassert(archreg < 8);
sewardjeeb9ef82004-07-15 12:39:03 +0000561 stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
sewardjd1061ab2004-07-08 01:45:30 +0000562}
563
sewardj063f02f2004-10-20 12:36:12 +0000564static IRExpr* getSReg ( UInt sreg )
565{
566 return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
567}
568
569static void putSReg ( UInt sreg, IRExpr* e )
570{
sewardjdd40fdf2006-12-24 02:20:24 +0000571 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
sewardj063f02f2004-10-20 12:36:12 +0000572 stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
573}
574
sewardjc9a43662004-11-30 18:51:59 +0000575static IRExpr* getXMMReg ( UInt xmmreg )
576{
577 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
578}
579
sewardj67e002d2004-12-02 18:16:33 +0000580static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
581{
582 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
583}
584
sewardjfd226452004-12-07 19:02:18 +0000585static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
sewardj67e002d2004-12-02 18:16:33 +0000586{
sewardjfd226452004-12-07 19:02:18 +0000587 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
sewardj67e002d2004-12-02 18:16:33 +0000588}
589
sewardj9636b442004-12-04 01:38:37 +0000590static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
591{
592 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
593}
594
sewardjfd226452004-12-07 19:02:18 +0000595static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
596{
597 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
598}
599
sewardjc9a43662004-11-30 18:51:59 +0000600static void putXMMReg ( UInt xmmreg, IRExpr* e )
601{
sewardjdd40fdf2006-12-24 02:20:24 +0000602 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_V128);
sewardjc9a43662004-11-30 18:51:59 +0000603 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
604}
605
sewardj67e002d2004-12-02 18:16:33 +0000606static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
607{
sewardjdd40fdf2006-12-24 02:20:24 +0000608 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj67e002d2004-12-02 18:16:33 +0000609 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
610}
611
sewardjfd226452004-12-07 19:02:18 +0000612static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
613{
sewardjdd40fdf2006-12-24 02:20:24 +0000614 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F64);
sewardjfd226452004-12-07 19:02:18 +0000615 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
616}
617
sewardj4cb918d2004-12-03 19:43:31 +0000618static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
sewardj67e002d2004-12-02 18:16:33 +0000619{
sewardjdd40fdf2006-12-24 02:20:24 +0000620 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +0000621 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
622}
623
sewardj9636b442004-12-04 01:38:37 +0000624static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
625{
sewardjdd40fdf2006-12-24 02:20:24 +0000626 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
sewardj9636b442004-12-04 01:38:37 +0000627 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
628}
629
sewardje5854d62004-12-09 03:44:34 +0000630static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
631{
sewardjdd40fdf2006-12-24 02:20:24 +0000632 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
sewardje5854d62004-12-09 03:44:34 +0000633 stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
634}
635
sewardj41f43bc2004-07-08 14:23:22 +0000636static void assign ( IRTemp dst, IRExpr* e )
sewardjd1061ab2004-07-08 01:45:30 +0000637{
sewardjdd40fdf2006-12-24 02:20:24 +0000638 stmt( IRStmt_WrTmp(dst, e) );
sewardjd1061ab2004-07-08 01:45:30 +0000639}
640
sewardj41f43bc2004-07-08 14:23:22 +0000641static void storeLE ( IRExpr* addr, IRExpr* data )
sewardjd1061ab2004-07-08 01:45:30 +0000642{
sewardje768e922009-11-26 17:17:37 +0000643 stmt( IRStmt_Store(Iend_LE, addr, data) );
sewardjd1061ab2004-07-08 01:45:30 +0000644}
645
sewardje87b4842004-07-10 12:23:30 +0000646static IRExpr* unop ( IROp op, IRExpr* a )
647{
648 return IRExpr_Unop(op, a);
649}
650
sewardjd1061ab2004-07-08 01:45:30 +0000651static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
652{
653 return IRExpr_Binop(op, a1, a2);
654}
655
sewardjf1b5b1a2006-02-03 22:54:17 +0000656static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
657{
658 return IRExpr_Triop(op, a1, a2, a3);
659}
660
sewardjd1061ab2004-07-08 01:45:30 +0000661static IRExpr* mkexpr ( IRTemp tmp )
662{
sewardjdd40fdf2006-12-24 02:20:24 +0000663 return IRExpr_RdTmp(tmp);
sewardjd1061ab2004-07-08 01:45:30 +0000664}
665
sewardjc2ac51e2004-07-12 01:03:26 +0000666static IRExpr* mkU8 ( UInt i )
667{
668 vassert(i < 256);
sewardj2d49b432005-02-01 00:37:06 +0000669 return IRExpr_Const(IRConst_U8( (UChar)i ));
sewardjc2ac51e2004-07-12 01:03:26 +0000670}
671
672static IRExpr* mkU16 ( UInt i )
673{
674 vassert(i < 65536);
sewardj2d49b432005-02-01 00:37:06 +0000675 return IRExpr_Const(IRConst_U16( (UShort)i ));
sewardjc2ac51e2004-07-12 01:03:26 +0000676}
677
sewardjd1061ab2004-07-08 01:45:30 +0000678static IRExpr* mkU32 ( UInt i )
679{
680 return IRExpr_Const(IRConst_U32(i));
sewardjc9a65702004-07-07 16:32:57 +0000681}
682
sewardj95535fe2004-12-15 17:42:58 +0000683static IRExpr* mkU64 ( ULong i )
684{
685 return IRExpr_Const(IRConst_U64(i));
686}
687
sewardj41f43bc2004-07-08 14:23:22 +0000688static IRExpr* mkU ( IRType ty, UInt i )
689{
sewardjc2ac51e2004-07-12 01:03:26 +0000690 if (ty == Ity_I8) return mkU8(i);
691 if (ty == Ity_I16) return mkU16(i);
692 if (ty == Ity_I32) return mkU32(i);
sewardje90ad6a2004-07-10 19:02:10 +0000693 /* If this panics, it usually means you passed a size (1,2,4)
694 value as the IRType, rather than a real IRType. */
sewardj41f43bc2004-07-08 14:23:22 +0000695 vpanic("mkU(x86)");
696}
697
sewardj1e6ad742004-12-02 16:16:11 +0000698static IRExpr* mkV128 ( UShort mask )
699{
700 return IRExpr_Const(IRConst_V128(mask));
701}
702
sewardje768e922009-11-26 17:17:37 +0000703static IRExpr* loadLE ( IRType ty, IRExpr* addr )
sewardj41f43bc2004-07-08 14:23:22 +0000704{
sewardje768e922009-11-26 17:17:37 +0000705 return IRExpr_Load(Iend_LE, ty, addr);
sewardj41f43bc2004-07-08 14:23:22 +0000706}
707
708static IROp mkSizedOp ( IRType ty, IROp op8 )
709{
sewardje05c42c2004-07-08 20:25:10 +0000710 Int adj;
sewardj41f43bc2004-07-08 14:23:22 +0000711 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
712 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
sewardj41f43bc2004-07-08 14:23:22 +0000713 || op8 == Iop_Mul8
714 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
sewardj5bd4d162004-11-10 13:02:48 +0000715 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
sewardje90ad6a2004-07-10 19:02:10 +0000716 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj1fb8c922009-07-12 12:56:53 +0000717 || op8 == Iop_CasCmpNE8
sewardjeb17e492007-08-25 23:07:44 +0000718 || op8 == Iop_Not8);
sewardje05c42c2004-07-08 20:25:10 +0000719 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
720 return adj + op8;
sewardj41f43bc2004-07-08 14:23:22 +0000721}
722
sewardj9334b0f2004-07-10 22:43:54 +0000723static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
sewardj41f43bc2004-07-08 14:23:22 +0000724{
sewardj9334b0f2004-07-10 22:43:54 +0000725 if (szSmall == 1 && szBig == 4) {
726 return signd ? Iop_8Sto32 : Iop_8Uto32;
sewardj41f43bc2004-07-08 14:23:22 +0000727 }
sewardj9334b0f2004-07-10 22:43:54 +0000728 if (szSmall == 1 && szBig == 2) {
729 return signd ? Iop_8Sto16 : Iop_8Uto16;
730 }
731 if (szSmall == 2 && szBig == 4) {
732 return signd ? Iop_16Sto32 : Iop_16Uto32;
733 }
sewardj948d48b2004-11-05 19:49:09 +0000734 vpanic("mkWidenOp(x86,guest)");
sewardj41f43bc2004-07-08 14:23:22 +0000735}
736
sewardjbaa66082005-08-23 17:29:27 +0000737static IRExpr* mkAnd1 ( IRExpr* x, IRExpr* y )
738{
sewardjdd40fdf2006-12-24 02:20:24 +0000739 vassert(typeOfIRExpr(irsb->tyenv,x) == Ity_I1);
740 vassert(typeOfIRExpr(irsb->tyenv,y) == Ity_I1);
sewardjbaa66082005-08-23 17:29:27 +0000741 return unop(Iop_32to1,
742 binop(Iop_And32,
743 unop(Iop_1Uto32,x),
744 unop(Iop_1Uto32,y)));
745}
746
sewardje9d8a262009-07-01 08:06:34 +0000747/* Generate a compare-and-swap operation, operating on memory at
748 'addr'. The expected value is 'expVal' and the new value is
749 'newVal'. If the operation fails, then transfer control (with a
750 no-redir jump (XXX no -- see comment at top of this file)) to
751 'restart_point', which is presumably the address of the guest
752 instruction again -- retrying, essentially. */
753static void casLE ( IRExpr* addr, IRExpr* expVal, IRExpr* newVal,
754 Addr32 restart_point )
755{
756 IRCAS* cas;
757 IRType tyE = typeOfIRExpr(irsb->tyenv, expVal);
758 IRType tyN = typeOfIRExpr(irsb->tyenv, newVal);
759 IRTemp oldTmp = newTemp(tyE);
760 IRTemp expTmp = newTemp(tyE);
761 vassert(tyE == tyN);
762 vassert(tyE == Ity_I32 || tyE == Ity_I16 || tyE == Ity_I8);
763 assign(expTmp, expVal);
764 cas = mkIRCAS( IRTemp_INVALID, oldTmp, Iend_LE, addr,
765 NULL, mkexpr(expTmp), NULL, newVal );
766 stmt( IRStmt_CAS(cas) );
767 stmt( IRStmt_Exit(
sewardj1fb8c922009-07-12 12:56:53 +0000768 binop( mkSizedOp(tyE,Iop_CasCmpNE8),
769 mkexpr(oldTmp), mkexpr(expTmp) ),
sewardje9d8a262009-07-01 08:06:34 +0000770 Ijk_Boring, /*Ijk_NoRedir*/
771 IRConst_U32( restart_point )
772 ));
773}
774
sewardj41f43bc2004-07-08 14:23:22 +0000775
776/*------------------------------------------------------------*/
777/*--- Helpers for %eflags. ---*/
778/*------------------------------------------------------------*/
779
sewardj0611d802004-07-11 02:37:54 +0000780/* -------------- Evaluating the flags-thunk. -------------- */
sewardjc9a65702004-07-07 16:32:57 +0000781
sewardje87b4842004-07-10 12:23:30 +0000782/* Build IR to calculate all the eflags from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000783 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
784 Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000785static IRExpr* mk_x86g_calculate_eflags_all ( void )
sewardje87b4842004-07-10 12:23:30 +0000786{
sewardjf9655262004-10-31 20:02:16 +0000787 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000788 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
789 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
790 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
791 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000792 IRExpr* call
793 = mkIRExprCCall(
794 Ity_I32,
795 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000796 "x86g_calculate_eflags_all", &x86g_calculate_eflags_all,
sewardj43c56462004-11-06 12:17:57 +0000797 args
798 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000799 /* Exclude OP and NDEP from definedness checking. We're only
800 interested in DEP1 and DEP2. */
801 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000802 return call;
sewardje87b4842004-07-10 12:23:30 +0000803}
804
sewardj84ff0652004-08-23 16:16:08 +0000805/* Build IR to calculate some particular condition from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000806 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
807 Ity_Bit. */
sewardj2a9ad022004-11-25 02:46:58 +0000808static IRExpr* mk_x86g_calculate_condition ( X86Condcode cond )
sewardj84ff0652004-08-23 16:16:08 +0000809{
sewardjf9655262004-10-31 20:02:16 +0000810 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000811 = mkIRExprVec_5( mkU32(cond),
sewardjf9655262004-10-31 20:02:16 +0000812 IRExpr_Get(OFFB_CC_OP, Ity_I32),
sewardj2a2ba8b2004-11-08 13:14:06 +0000813 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
814 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
815 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000816 IRExpr* call
817 = mkIRExprCCall(
818 Ity_I32,
819 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000820 "x86g_calculate_condition", &x86g_calculate_condition,
sewardj43c56462004-11-06 12:17:57 +0000821 args
822 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000823 /* Exclude the requested condition, OP and NDEP from definedness
824 checking. We're only interested in DEP1 and DEP2. */
825 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardj43c56462004-11-06 12:17:57 +0000826 return unop(Iop_32to1, call);
827}
828
829/* Build IR to calculate just the carry flag from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000830 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000831static IRExpr* mk_x86g_calculate_eflags_c ( void )
sewardj43c56462004-11-06 12:17:57 +0000832{
833 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000834 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
835 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
836 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
837 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000838 IRExpr* call
839 = mkIRExprCCall(
840 Ity_I32,
sewardj893a3302005-01-24 10:49:02 +0000841 3/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000842 "x86g_calculate_eflags_c", &x86g_calculate_eflags_c,
sewardj43c56462004-11-06 12:17:57 +0000843 args
844 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000845 /* Exclude OP and NDEP from definedness checking. We're only
846 interested in DEP1 and DEP2. */
847 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000848 return call;
sewardj84ff0652004-08-23 16:16:08 +0000849}
850
sewardje87b4842004-07-10 12:23:30 +0000851
sewardj0611d802004-07-11 02:37:54 +0000852/* -------------- Building the flags-thunk. -------------- */
853
sewardjb9c5cf62004-08-24 15:10:38 +0000854/* The machinery in this section builds the flag-thunk following a
855 flag-setting operation. Hence the various setFlags_* functions.
sewardjb9c5cf62004-08-24 15:10:38 +0000856*/
857
858static Bool isAddSub ( IROp op8 )
859{
sewardj2d49b432005-02-01 00:37:06 +0000860 return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
sewardjb9c5cf62004-08-24 15:10:38 +0000861}
sewardj0611d802004-07-11 02:37:54 +0000862
sewardj2a2ba8b2004-11-08 13:14:06 +0000863static Bool isLogic ( IROp op8 )
864{
sewardj2d49b432005-02-01 00:37:06 +0000865 return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000866}
867
sewardja2384712004-07-29 14:36:40 +0000868/* U-widen 8/16/32 bit int expr to 32. */
sewardjc22a6fd2004-07-29 23:41:47 +0000869static IRExpr* widenUto32 ( IRExpr* e )
sewardj443cd9d2004-07-18 23:06:45 +0000870{
sewardjdd40fdf2006-12-24 02:20:24 +0000871 switch (typeOfIRExpr(irsb->tyenv,e)) {
sewardj443cd9d2004-07-18 23:06:45 +0000872 case Ity_I32: return e;
873 case Ity_I16: return unop(Iop_16Uto32,e);
874 case Ity_I8: return unop(Iop_8Uto32,e);
875 default: vpanic("widenUto32");
876 }
877}
878
sewardjc22a6fd2004-07-29 23:41:47 +0000879/* S-widen 8/16/32 bit int expr to 32. */
880static IRExpr* widenSto32 ( IRExpr* e )
881{
sewardjdd40fdf2006-12-24 02:20:24 +0000882 switch (typeOfIRExpr(irsb->tyenv,e)) {
sewardjc22a6fd2004-07-29 23:41:47 +0000883 case Ity_I32: return e;
884 case Ity_I16: return unop(Iop_16Sto32,e);
885 case Ity_I8: return unop(Iop_8Sto32,e);
886 default: vpanic("widenSto32");
887 }
888}
889
sewardja2384712004-07-29 14:36:40 +0000890/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
891 of these combinations make sense. */
892static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
893{
sewardjdd40fdf2006-12-24 02:20:24 +0000894 IRType src_ty = typeOfIRExpr(irsb->tyenv,e);
sewardja2384712004-07-29 14:36:40 +0000895 if (src_ty == dst_ty)
896 return e;
897 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
898 return unop(Iop_32to16, e);
899 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
900 return unop(Iop_32to8, e);
901
902 vex_printf("\nsrc, dst tys are: ");
903 ppIRType(src_ty);
904 vex_printf(", ");
905 ppIRType(dst_ty);
906 vex_printf("\n");
907 vpanic("narrowTo(x86)");
908}
909
sewardj443cd9d2004-07-18 23:06:45 +0000910
sewardj2a2ba8b2004-11-08 13:14:06 +0000911/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
sewardj948d48b2004-11-05 19:49:09 +0000912 auto-sized up to the real op. */
sewardj0611d802004-07-11 02:37:54 +0000913
sewardj2a2ba8b2004-11-08 13:14:06 +0000914static
915void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000916{
sewardjb9c5cf62004-08-24 15:10:38 +0000917 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
918
919 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
920
921 switch (op8) {
sewardj2a9ad022004-11-25 02:46:58 +0000922 case Iop_Add8: ccOp += X86G_CC_OP_ADDB; break;
923 case Iop_Sub8: ccOp += X86G_CC_OP_SUBB; break;
sewardjb9c5cf62004-08-24 15:10:38 +0000924 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000925 vpanic("setFlags_DEP1_DEP2(x86)");
sewardjb9c5cf62004-08-24 15:10:38 +0000926 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000927 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
928 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
929 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
sewardja3b7e3a2005-04-05 01:54:19 +0000930 /* Set NDEP even though it isn't used. This makes redundant-PUT
931 elimination of previous stores to this field work better. */
932 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjb9c5cf62004-08-24 15:10:38 +0000933}
934
935
sewardj2a2ba8b2004-11-08 13:14:06 +0000936/* Set the OP and DEP1 fields only, and write zero to DEP2. */
sewardjb9c5cf62004-08-24 15:10:38 +0000937
sewardj2a2ba8b2004-11-08 13:14:06 +0000938static
939void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
sewardjb9c5cf62004-08-24 15:10:38 +0000940{
941 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj0611d802004-07-11 02:37:54 +0000942
943 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
944
945 switch (op8) {
946 case Iop_Or8:
947 case Iop_And8:
sewardj2a9ad022004-11-25 02:46:58 +0000948 case Iop_Xor8: ccOp += X86G_CC_OP_LOGICB; break;
sewardj0611d802004-07-11 02:37:54 +0000949 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000950 vpanic("setFlags_DEP1(x86)");
sewardj0611d802004-07-11 02:37:54 +0000951 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000952 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
953 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
954 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardja3b7e3a2005-04-05 01:54:19 +0000955 /* Set NDEP even though it isn't used. This makes redundant-PUT
956 elimination of previous stores to this field work better. */
957 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj0611d802004-07-11 02:37:54 +0000958}
959
960
sewardj948d48b2004-11-05 19:49:09 +0000961/* For shift operations, we put in the result and the undershifted
962 result. Except if the shift amount is zero, the thunk is left
963 unchanged. */
sewardj0611d802004-07-11 02:37:54 +0000964
sewardj2a2ba8b2004-11-08 13:14:06 +0000965static void setFlags_DEP1_DEP2_shift ( IROp op32,
966 IRTemp res,
967 IRTemp resUS,
968 IRType ty,
969 IRTemp guard )
sewardj0611d802004-07-11 02:37:54 +0000970{
sewardjc22a6fd2004-07-29 23:41:47 +0000971 Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
sewardj0611d802004-07-11 02:37:54 +0000972
973 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
974 vassert(guard);
975
sewardj2a2ba8b2004-11-08 13:14:06 +0000976 /* Both kinds of right shifts are handled by the same thunk
977 operation. */
sewardjc22a6fd2004-07-29 23:41:47 +0000978 switch (op32) {
979 case Iop_Shr32:
sewardj2a9ad022004-11-25 02:46:58 +0000980 case Iop_Sar32: ccOp = X86G_CC_OP_SHRL - ccOp; break;
981 case Iop_Shl32: ccOp = X86G_CC_OP_SHLL - ccOp; break;
sewardjc22a6fd2004-07-29 23:41:47 +0000982 default: ppIROp(op32);
sewardj2a2ba8b2004-11-08 13:14:06 +0000983 vpanic("setFlags_DEP1_DEP2_shift(x86)");
sewardj0611d802004-07-11 02:37:54 +0000984 }
985
sewardj2a2ba8b2004-11-08 13:14:06 +0000986 /* DEP1 contains the result, DEP2 contains the undershifted value. */
sewardjeeb9ef82004-07-15 12:39:03 +0000987 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj4042c7e2004-07-18 01:28:30 +0000988 IRExpr_Mux0X( mkexpr(guard),
989 IRExpr_Get(OFFB_CC_OP,Ity_I32),
990 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000991 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj4042c7e2004-07-18 01:28:30 +0000992 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000993 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000994 widenUto32(mkexpr(res)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000995 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj4042c7e2004-07-18 01:28:30 +0000996 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000997 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000998 widenUto32(mkexpr(resUS)))) );
sewardja3b7e3a2005-04-05 01:54:19 +0000999 /* Set NDEP even though it isn't used. This makes redundant-PUT
1000 elimination of previous stores to this field work better. */
1001 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj0611d802004-07-11 02:37:54 +00001002}
1003
1004
sewardj2a2ba8b2004-11-08 13:14:06 +00001005/* For the inc/dec case, we store in DEP1 the result value and in NDEP
sewardj948d48b2004-11-05 19:49:09 +00001006 the former value of the carry flag, which unfortunately we have to
1007 compute. */
sewardj0611d802004-07-11 02:37:54 +00001008
sewardj948d48b2004-11-05 19:49:09 +00001009static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
sewardj0611d802004-07-11 02:37:54 +00001010{
sewardj2a9ad022004-11-25 02:46:58 +00001011 Int ccOp = inc ? X86G_CC_OP_INCB : X86G_CC_OP_DECB;
sewardj0611d802004-07-11 02:37:54 +00001012
1013 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
1014 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
1015
1016 /* This has to come first, because calculating the C flag
sewardj2a2ba8b2004-11-08 13:14:06 +00001017 may require reading all four thunk fields. */
sewardj2a9ad022004-11-25 02:46:58 +00001018 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_x86g_calculate_eflags_c()) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001019 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
sewardj478646f2008-05-01 20:13:04 +00001020 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(res))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001021 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardj0611d802004-07-11 02:37:54 +00001022}
1023
1024
sewardj2a2ba8b2004-11-08 13:14:06 +00001025/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1026 two arguments. */
sewardjcf780b42004-07-13 18:42:17 +00001027
1028static
sewardj2a2ba8b2004-11-08 13:14:06 +00001029void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
sewardjcf780b42004-07-13 18:42:17 +00001030{
1031 switch (ty) {
sewardj2a2ba8b2004-11-08 13:14:06 +00001032 case Ity_I8:
1033 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
1034 break;
1035 case Ity_I16:
1036 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
1037 break;
1038 case Ity_I32:
1039 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
1040 break;
1041 default:
1042 vpanic("setFlags_MUL(x86)");
sewardjcf780b42004-07-13 18:42:17 +00001043 }
sewardj2a2ba8b2004-11-08 13:14:06 +00001044 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
1045 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
sewardja3b7e3a2005-04-05 01:54:19 +00001046 /* Set NDEP even though it isn't used. This makes redundant-PUT
1047 elimination of previous stores to this field work better. */
1048 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjcf780b42004-07-13 18:42:17 +00001049}
1050
1051
sewardj3af115f2004-07-14 02:46:52 +00001052/* -------------- Condition codes. -------------- */
1053
sewardje87b4842004-07-10 12:23:30 +00001054/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +00001055
sewardj2d49b432005-02-01 00:37:06 +00001056static HChar* name_X86Condcode ( X86Condcode cond )
sewardje87b4842004-07-10 12:23:30 +00001057{
1058 switch (cond) {
sewardj2a9ad022004-11-25 02:46:58 +00001059 case X86CondO: return "o";
1060 case X86CondNO: return "no";
1061 case X86CondB: return "b";
1062 case X86CondNB: return "nb";
1063 case X86CondZ: return "z";
1064 case X86CondNZ: return "nz";
1065 case X86CondBE: return "be";
1066 case X86CondNBE: return "nbe";
1067 case X86CondS: return "s";
1068 case X86CondNS: return "ns";
1069 case X86CondP: return "p";
1070 case X86CondNP: return "np";
1071 case X86CondL: return "l";
1072 case X86CondNL: return "nl";
1073 case X86CondLE: return "le";
1074 case X86CondNLE: return "nle";
1075 case X86CondAlways: return "ALWAYS";
1076 default: vpanic("name_X86Condcode");
sewardje87b4842004-07-10 12:23:30 +00001077 }
1078}
1079
sewardj2a9ad022004-11-25 02:46:58 +00001080static
1081X86Condcode positiveIse_X86Condcode ( X86Condcode cond,
sewardjdbf550c2005-01-24 11:54:11 +00001082 Bool* needInvert )
sewardje87b4842004-07-10 12:23:30 +00001083{
sewardj2a9ad022004-11-25 02:46:58 +00001084 vassert(cond >= X86CondO && cond <= X86CondNLE);
sewardje87b4842004-07-10 12:23:30 +00001085 if (cond & 1) {
1086 *needInvert = True;
1087 return cond-1;
1088 } else {
1089 *needInvert = False;
1090 return cond;
1091 }
1092}
1093
1094
sewardj3af115f2004-07-14 02:46:52 +00001095/* -------------- Helpers for ADD/SUB with carry. -------------- */
1096
sewardj948d48b2004-11-05 19:49:09 +00001097/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001098 appropriately.
sewardje9d8a262009-07-01 08:06:34 +00001099
1100 Optionally, generate a store for the 'tres' value. This can either
1101 be a normal store, or it can be a cas-with-possible-failure style
1102 store:
1103
1104 if taddr is IRTemp_INVALID, then no store is generated.
1105
1106 if taddr is not IRTemp_INVALID, then a store (using taddr as
1107 the address) is generated:
1108
1109 if texpVal is IRTemp_INVALID then a normal store is
1110 generated, and restart_point must be zero (it is irrelevant).
1111
1112 if texpVal is not IRTemp_INVALID then a cas-style store is
1113 generated. texpVal is the expected value, restart_point
1114 is the restart point if the store fails, and texpVal must
1115 have the same type as tres.
sewardj3af115f2004-07-14 02:46:52 +00001116*/
1117static void helper_ADC ( Int sz,
sewardje9d8a262009-07-01 08:06:34 +00001118 IRTemp tres, IRTemp ta1, IRTemp ta2,
1119 /* info about optional store: */
1120 IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
sewardj3af115f2004-07-14 02:46:52 +00001121{
1122 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001123 IRType ty = szToITy(sz);
1124 IRTemp oldc = newTemp(Ity_I32);
1125 IRTemp oldcn = newTemp(ty);
1126 IROp plus = mkSizedOp(ty, Iop_Add8);
1127 IROp xor = mkSizedOp(ty, Iop_Xor8);
sewardja2384712004-07-29 14:36:40 +00001128
sewardje9d8a262009-07-01 08:06:34 +00001129 vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
sewardja2384712004-07-29 14:36:40 +00001130 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001131 thunkOp = sz==4 ? X86G_CC_OP_ADCL
1132 : (sz==2 ? X86G_CC_OP_ADCW : X86G_CC_OP_ADCB);
sewardj3af115f2004-07-14 02:46:52 +00001133
sewardj2a2ba8b2004-11-08 13:14:06 +00001134 /* oldc = old carry flag, 0 or 1 */
1135 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001136 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001137 mkU32(1)) );
sewardj3af115f2004-07-14 02:46:52 +00001138
sewardj2a2ba8b2004-11-08 13:14:06 +00001139 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1140
1141 assign( tres, binop(plus,
1142 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1143 mkexpr(oldcn)) );
1144
sewardje9d8a262009-07-01 08:06:34 +00001145 /* Possibly generate a store of 'tres' to 'taddr'. See comment at
1146 start of this function. */
1147 if (taddr != IRTemp_INVALID) {
1148 if (texpVal == IRTemp_INVALID) {
1149 vassert(restart_point == 0);
1150 storeLE( mkexpr(taddr), mkexpr(tres) );
1151 } else {
1152 vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1153 /* .. and hence 'texpVal' has the same type as 'tres'. */
1154 casLE( mkexpr(taddr),
1155 mkexpr(texpVal), mkexpr(tres), restart_point );
1156 }
1157 }
1158
sewardj2a2ba8b2004-11-08 13:14:06 +00001159 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
sewardj3b3eacd2005-08-24 10:01:36 +00001160 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1)) ));
1161 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
1162 mkexpr(oldcn)) )) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001163 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardj3af115f2004-07-14 02:46:52 +00001164}
1165
1166
sewardj948d48b2004-11-05 19:49:09 +00001167/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
sewardje9d8a262009-07-01 08:06:34 +00001168 appropriately. As with helper_ADC, possibly generate a store of
1169 the result -- see comments on helper_ADC for details.
sewardjcaca9d02004-07-28 07:11:32 +00001170*/
1171static void helper_SBB ( Int sz,
sewardje9d8a262009-07-01 08:06:34 +00001172 IRTemp tres, IRTemp ta1, IRTemp ta2,
1173 /* info about optional store: */
1174 IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
sewardjcaca9d02004-07-28 07:11:32 +00001175{
1176 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001177 IRType ty = szToITy(sz);
1178 IRTemp oldc = newTemp(Ity_I32);
1179 IRTemp oldcn = newTemp(ty);
1180 IROp minus = mkSizedOp(ty, Iop_Sub8);
1181 IROp xor = mkSizedOp(ty, Iop_Xor8);
1182
sewardje9d8a262009-07-01 08:06:34 +00001183 vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
sewardj2a2ba8b2004-11-08 13:14:06 +00001184 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001185 thunkOp = sz==4 ? X86G_CC_OP_SBBL
1186 : (sz==2 ? X86G_CC_OP_SBBW : X86G_CC_OP_SBBB);
sewardjcaca9d02004-07-28 07:11:32 +00001187
1188 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +00001189 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001190 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001191 mkU32(1)) );
sewardjcaca9d02004-07-28 07:11:32 +00001192
sewardj2a2ba8b2004-11-08 13:14:06 +00001193 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
sewardja2384712004-07-29 14:36:40 +00001194
sewardj2a2ba8b2004-11-08 13:14:06 +00001195 assign( tres, binop(minus,
1196 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1197 mkexpr(oldcn)) );
sewardjcaca9d02004-07-28 07:11:32 +00001198
sewardje9d8a262009-07-01 08:06:34 +00001199 /* Possibly generate a store of 'tres' to 'taddr'. See comment at
1200 start of this function. */
1201 if (taddr != IRTemp_INVALID) {
1202 if (texpVal == IRTemp_INVALID) {
1203 vassert(restart_point == 0);
1204 storeLE( mkexpr(taddr), mkexpr(tres) );
1205 } else {
1206 vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1207 /* .. and hence 'texpVal' has the same type as 'tres'. */
1208 casLE( mkexpr(taddr),
1209 mkexpr(texpVal), mkexpr(tres), restart_point );
1210 }
1211 }
1212
sewardj2a2ba8b2004-11-08 13:14:06 +00001213 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
sewardj3b3eacd2005-08-24 10:01:36 +00001214 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1) )) );
1215 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
1216 mkexpr(oldcn)) )) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001217 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardjcaca9d02004-07-28 07:11:32 +00001218}
1219
1220
sewardj7dd2eb22005-01-05 10:38:54 +00001221/* -------------- Helpers for disassembly printing. -------------- */
sewardj41f43bc2004-07-08 14:23:22 +00001222
sewardjc9a43662004-11-30 18:51:59 +00001223static HChar* nameGrp1 ( Int opc_aux )
sewardj41f43bc2004-07-08 14:23:22 +00001224{
sewardjc9a43662004-11-30 18:51:59 +00001225 static HChar* grp1_names[8]
sewardj41f43bc2004-07-08 14:23:22 +00001226 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1227 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1228 return grp1_names[opc_aux];
1229}
1230
sewardjc9a43662004-11-30 18:51:59 +00001231static HChar* nameGrp2 ( Int opc_aux )
sewardje90ad6a2004-07-10 19:02:10 +00001232{
sewardjc9a43662004-11-30 18:51:59 +00001233 static HChar* grp2_names[8]
sewardje90ad6a2004-07-10 19:02:10 +00001234 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +00001235 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +00001236 return grp2_names[opc_aux];
1237}
1238
sewardjc9a43662004-11-30 18:51:59 +00001239static HChar* nameGrp4 ( Int opc_aux )
sewardjc2ac51e2004-07-12 01:03:26 +00001240{
sewardjc9a43662004-11-30 18:51:59 +00001241 static HChar* grp4_names[8]
sewardjc2ac51e2004-07-12 01:03:26 +00001242 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1243 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1244 return grp4_names[opc_aux];
1245}
sewardj0611d802004-07-11 02:37:54 +00001246
sewardjc9a43662004-11-30 18:51:59 +00001247static HChar* nameGrp5 ( Int opc_aux )
sewardj0611d802004-07-11 02:37:54 +00001248{
sewardjc9a43662004-11-30 18:51:59 +00001249 static HChar* grp5_names[8]
sewardj0611d802004-07-11 02:37:54 +00001250 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1251 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1252 return grp5_names[opc_aux];
1253}
1254
sewardj490ad382005-03-13 17:25:53 +00001255static HChar* nameGrp8 ( Int opc_aux )
1256{
1257 static HChar* grp8_names[8]
1258 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1259 if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(x86)");
1260 return grp8_names[opc_aux];
1261}
sewardjc9a65702004-07-07 16:32:57 +00001262
sewardjc9a43662004-11-30 18:51:59 +00001263static HChar* nameIReg ( Int size, Int reg )
sewardjc9a65702004-07-07 16:32:57 +00001264{
sewardjc9a43662004-11-30 18:51:59 +00001265 static HChar* ireg32_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001266 = { "%eax", "%ecx", "%edx", "%ebx",
1267 "%esp", "%ebp", "%esi", "%edi" };
sewardjc9a43662004-11-30 18:51:59 +00001268 static HChar* ireg16_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001269 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
sewardjc9a43662004-11-30 18:51:59 +00001270 static HChar* ireg8_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001271 = { "%al", "%cl", "%dl", "%bl",
1272 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1273 if (reg < 0 || reg > 7) goto bad;
1274 switch (size) {
1275 case 4: return ireg32_names[reg];
1276 case 2: return ireg16_names[reg];
1277 case 1: return ireg8_names[reg];
1278 }
1279 bad:
1280 vpanic("nameIReg(X86)");
1281 return NULL; /*notreached*/
1282}
1283
sewardjc9a43662004-11-30 18:51:59 +00001284static HChar* nameSReg ( UInt sreg )
sewardj063f02f2004-10-20 12:36:12 +00001285{
1286 switch (sreg) {
1287 case R_ES: return "%es";
1288 case R_CS: return "%cs";
1289 case R_SS: return "%ss";
1290 case R_DS: return "%ds";
1291 case R_FS: return "%fs";
1292 case R_GS: return "%gs";
1293 default: vpanic("nameSReg(x86)");
1294 }
1295}
1296
sewardjc9a43662004-11-30 18:51:59 +00001297static HChar* nameMMXReg ( Int mmxreg )
sewardj464efa42004-11-19 22:17:29 +00001298{
sewardjc9a43662004-11-30 18:51:59 +00001299 static HChar* mmx_names[8]
sewardj464efa42004-11-19 22:17:29 +00001300 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1301 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1302 return mmx_names[mmxreg];
1303}
1304
sewardjc9a43662004-11-30 18:51:59 +00001305static HChar* nameXMMReg ( Int xmmreg )
1306{
1307 static HChar* xmm_names[8]
1308 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1309 "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1310 if (xmmreg < 0 || xmmreg > 7) vpanic("name_of_xmm_reg");
1311 return xmm_names[xmmreg];
1312}
sewardj464efa42004-11-19 22:17:29 +00001313
sewardj2d49b432005-02-01 00:37:06 +00001314static HChar* nameMMXGran ( Int gran )
sewardj464efa42004-11-19 22:17:29 +00001315{
1316 switch (gran) {
1317 case 0: return "b";
1318 case 1: return "w";
1319 case 2: return "d";
1320 case 3: return "q";
1321 default: vpanic("nameMMXGran(x86,guest)");
1322 }
1323}
sewardjc9a65702004-07-07 16:32:57 +00001324
sewardj2d49b432005-02-01 00:37:06 +00001325static HChar nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001326{
1327 switch (size) {
1328 case 4: return 'l';
1329 case 2: return 'w';
1330 case 1: return 'b';
1331 default: vpanic("nameISize(x86)");
1332 }
1333}
1334
sewardjd1061ab2004-07-08 01:45:30 +00001335
1336/*------------------------------------------------------------*/
1337/*--- JMP helpers ---*/
1338/*------------------------------------------------------------*/
1339
sewardj78c19df2004-07-12 22:49:27 +00001340static void jmp_lit( IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001341{
sewardjdd40fdf2006-12-24 02:20:24 +00001342 irsb->next = mkU32(d32);
1343 irsb->jumpkind = kind;
sewardjd1061ab2004-07-08 01:45:30 +00001344}
1345
sewardj78c19df2004-07-12 22:49:27 +00001346static void jmp_treg( IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001347{
sewardjdd40fdf2006-12-24 02:20:24 +00001348 irsb->next = mkexpr(t);
1349 irsb->jumpkind = kind;
sewardje05c42c2004-07-08 20:25:10 +00001350}
sewardje87b4842004-07-10 12:23:30 +00001351
sewardj2a9ad022004-11-25 02:46:58 +00001352static
1353void jcc_01( X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001354{
sewardj2a9ad022004-11-25 02:46:58 +00001355 Bool invert;
1356 X86Condcode condPos;
1357 condPos = positiveIse_X86Condcode ( cond, &invert );
sewardje87b4842004-07-10 12:23:30 +00001358 if (invert) {
sewardj2a9ad022004-11-25 02:46:58 +00001359 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001360 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001361 IRConst_U32(d32_false) ) );
sewardjdd40fdf2006-12-24 02:20:24 +00001362 irsb->next = mkU32(d32_true);
1363 irsb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001364 } else {
sewardj2a9ad022004-11-25 02:46:58 +00001365 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001366 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001367 IRConst_U32(d32_true) ) );
sewardjdd40fdf2006-12-24 02:20:24 +00001368 irsb->next = mkU32(d32_false);
1369 irsb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001370 }
1371}
sewardjc9a65702004-07-07 16:32:57 +00001372
1373
sewardjd1061ab2004-07-08 01:45:30 +00001374/*------------------------------------------------------------*/
1375/*--- Disassembling addressing modes ---*/
1376/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001377
sewardjd1061ab2004-07-08 01:45:30 +00001378static
sewardj2d49b432005-02-01 00:37:06 +00001379HChar* sorbTxt ( UChar sorb )
sewardjd1061ab2004-07-08 01:45:30 +00001380{
1381 switch (sorb) {
1382 case 0: return ""; /* no override */
1383 case 0x3E: return "%ds";
1384 case 0x26: return "%es:";
1385 case 0x64: return "%fs:";
1386 case 0x65: return "%gs:";
sewardj7df596b2004-12-06 14:29:12 +00001387 default: vpanic("sorbTxt(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001388 }
1389}
1390
1391
sewardj7df596b2004-12-06 14:29:12 +00001392/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
1393 linear address by adding any required segment override as indicated
1394 by sorb. */
sewardjd1061ab2004-07-08 01:45:30 +00001395static
1396IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1397{
sewardj3bd6f3e2004-12-13 10:48:19 +00001398 Int sreg;
1399 IRType hWordTy;
1400 IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
sewardjd1061ab2004-07-08 01:45:30 +00001401
1402 if (sorb == 0)
1403 /* the common case - no override */
1404 return virtual;
1405
sewardjd1061ab2004-07-08 01:45:30 +00001406 switch (sorb) {
1407 case 0x3E: sreg = R_DS; break;
1408 case 0x26: sreg = R_ES; break;
1409 case 0x64: sreg = R_FS; break;
1410 case 0x65: sreg = R_GS; break;
sewardj7df596b2004-12-06 14:29:12 +00001411 default: vpanic("handleSegOverride(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001412 }
1413
sewardj3bd6f3e2004-12-13 10:48:19 +00001414 hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
sewardjd1061ab2004-07-08 01:45:30 +00001415
sewardj3bd6f3e2004-12-13 10:48:19 +00001416 seg_selector = newTemp(Ity_I32);
1417 ldt_ptr = newTemp(hWordTy);
1418 gdt_ptr = newTemp(hWordTy);
1419 r64 = newTemp(Ity_I64);
sewardjd1061ab2004-07-08 01:45:30 +00001420
sewardj3bd6f3e2004-12-13 10:48:19 +00001421 assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
1422 assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
1423 assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
sewardj7df596b2004-12-06 14:29:12 +00001424
sewardj3bd6f3e2004-12-13 10:48:19 +00001425 /*
1426 Call this to do the translation and limit checks:
1427 ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
1428 UInt seg_selector, UInt virtual_addr )
1429 */
1430 assign(
1431 r64,
1432 mkIRExprCCall(
1433 Ity_I64,
1434 0/*regparms*/,
1435 "x86g_use_seg_selector",
1436 &x86g_use_seg_selector,
1437 mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
1438 mkexpr(seg_selector), virtual)
1439 )
1440 );
sewardj7df596b2004-12-06 14:29:12 +00001441
sewardj52444cb2004-12-13 14:09:01 +00001442 /* If the high 32 of the result are non-zero, there was a
1443 failure in address translation. In which case, make a
1444 quick exit.
1445 */
1446 stmt(
1447 IRStmt_Exit(
1448 binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
1449 Ijk_MapFail,
sewardj9e6491a2005-07-02 19:24:10 +00001450 IRConst_U32( guest_EIP_curr_instr )
sewardj52444cb2004-12-13 14:09:01 +00001451 )
1452 );
1453
1454 /* otherwise, here's the translated result. */
sewardj3bd6f3e2004-12-13 10:48:19 +00001455 return unop(Iop_64to32, mkexpr(r64));
sewardjd1061ab2004-07-08 01:45:30 +00001456}
1457
1458
1459/* Generate IR to calculate an address indicated by a ModRM and
1460 following SIB bytes. The expression, and the number of bytes in
1461 the address mode, are returned. Note that this fn should not be
1462 called if the R/M part of the address denotes a register instead of
1463 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001464 placed in buf.
1465
1466 The computed address is stored in a new tempreg, and the
1467 identity of the tempreg is returned. */
1468
1469static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1470{
1471 IRTemp tmp = newTemp(Ity_I32);
1472 assign( tmp, addr32 );
1473 return tmp;
1474}
sewardjd1061ab2004-07-08 01:45:30 +00001475
1476static
sewardj52d04912005-07-03 00:52:48 +00001477IRTemp disAMode ( Int* len, UChar sorb, Int delta, HChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001478{
1479 UChar mod_reg_rm = getIByte(delta);
1480 delta++;
1481
sewardj9ee82862004-12-14 01:16:59 +00001482 buf[0] = (UChar)0;
1483
sewardjd1061ab2004-07-08 01:45:30 +00001484 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1485 jump table seems a bit excessive.
1486 */
sewardj9b45b482005-02-07 01:42:18 +00001487 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1488 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1489 /* is now XX0XXYYY */
1490 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001491 switch (mod_reg_rm) {
1492
1493 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1494 --> GET %reg, t
1495 */
1496 case 0x00: case 0x01: case 0x02: case 0x03:
1497 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1498 { UChar rm = mod_reg_rm;
1499 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1500 *len = 1;
sewardj5bd4d162004-11-10 13:02:48 +00001501 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001502 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001503 }
1504
1505 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1506 --> GET %reg, t ; ADDL d8, t
1507 */
1508 case 0x08: case 0x09: case 0x0A: case 0x0B:
1509 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj9b45b482005-02-07 01:42:18 +00001510 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001511 UInt d = getSDisp8(delta);
sewardj2d49b432005-02-01 00:37:06 +00001512 DIS(buf, "%s%d(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001513 *len = 2;
1514 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001515 handleSegOverride(sorb,
1516 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001517 }
1518
1519 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1520 --> GET %reg, t ; ADDL d8, t
1521 */
1522 case 0x10: case 0x11: case 0x12: case 0x13:
1523 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj9b45b482005-02-07 01:42:18 +00001524 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001525 UInt d = getUDisp32(delta);
sewardj2d49b432005-02-01 00:37:06 +00001526 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001527 *len = 5;
1528 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001529 handleSegOverride(sorb,
1530 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001531 }
1532
1533 /* a register, %eax .. %edi. This shouldn't happen. */
1534 case 0x18: case 0x19: case 0x1A: case 0x1B:
1535 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1536 vpanic("disAMode(x86): not an addr!");
1537
1538 /* a 32-bit literal address
1539 --> MOV d32, tmp
1540 */
1541 case 0x05:
1542 { UInt d = getUDisp32(delta);
1543 *len = 5;
1544 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001545 return disAMode_copy2tmp(
1546 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001547 }
1548
1549 case 0x04: {
1550 /* SIB, with no displacement. Special cases:
1551 -- %esp cannot act as an index value.
1552 If index_r indicates %esp, zero is used for the index.
1553 -- when mod is zero and base indicates EBP, base is instead
1554 a 32-bit literal.
1555 It's all madness, I tell you. Extract %index, %base and
1556 scale from the SIB byte. The value denoted is then:
1557 | %index == %ESP && %base == %EBP
1558 = d32 following SIB byte
1559 | %index == %ESP && %base != %EBP
1560 = %base
1561 | %index != %ESP && %base == %EBP
1562 = d32 following SIB byte + (%index << scale)
1563 | %index != %ESP && %base != %ESP
1564 = %base + (%index << scale)
1565
1566 What happens to the souls of CPU architects who dream up such
1567 horrendous schemes, do you suppose?
1568 */
1569 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001570 UChar scale = toUChar((sib >> 6) & 3);
1571 UChar index_r = toUChar((sib >> 3) & 7);
1572 UChar base_r = toUChar(sib & 7);
sewardj5bd4d162004-11-10 13:02:48 +00001573 delta++;
sewardjd1061ab2004-07-08 01:45:30 +00001574
1575 if (index_r != R_ESP && base_r != R_EBP) {
1576 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1577 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001578 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001579 return
1580 disAMode_copy2tmp(
sewardj5bd4d162004-11-10 13:02:48 +00001581 handleSegOverride(sorb,
1582 binop(Iop_Add32,
sewardjd1061ab2004-07-08 01:45:30 +00001583 getIReg(4,base_r),
1584 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001585 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001586 }
1587
1588 if (index_r != R_ESP && base_r == R_EBP) {
1589 UInt d = getUDisp32(delta);
1590 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1591 nameIReg(4,index_r), 1<<scale);
1592 *len = 6;
1593 return
sewardj940e8c92004-07-11 16:53:24 +00001594 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001595 handleSegOverride(sorb,
sewardj5bd4d162004-11-10 13:02:48 +00001596 binop(Iop_Add32,
1597 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001598 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001599 }
1600
1601 if (index_r == R_ESP && base_r != R_EBP) {
1602 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001603 *len = 2;
1604 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001605 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001606 }
1607
1608 if (index_r == R_ESP && base_r == R_EBP) {
1609 UInt d = getUDisp32(delta);
sewardj9c3b25a2007-04-05 15:06:56 +00001610 DIS(buf, "%s0x%x(,,)", sorbTxt(sorb), d);
sewardj5bd4d162004-11-10 13:02:48 +00001611 *len = 6;
sewardj5bd4d162004-11-10 13:02:48 +00001612 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001613 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001614 }
sewardjba89f4c2005-04-07 17:31:27 +00001615 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001616 vassert(0);
1617 }
1618
1619 /* SIB, with 8-bit displacement. Special cases:
1620 -- %esp cannot act as an index value.
1621 If index_r indicates %esp, zero is used for the index.
1622 Denoted value is:
1623 | %index == %ESP
1624 = d8 + %base
1625 | %index != %ESP
1626 = d8 + %base + (%index << scale)
1627 */
1628 case 0x0C: {
1629 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001630 UChar scale = toUChar((sib >> 6) & 3);
1631 UChar index_r = toUChar((sib >> 3) & 7);
1632 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001633 UInt d = getSDisp8(delta+1);
1634
1635 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001636 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1637 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001638 *len = 3;
1639 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001640 handleSegOverride(sorb,
1641 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001642 } else {
sewardj2d49b432005-02-01 00:37:06 +00001643 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
sewardjd1061ab2004-07-08 01:45:30 +00001644 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001645 *len = 3;
1646 return
sewardj940e8c92004-07-11 16:53:24 +00001647 disAMode_copy2tmp(
1648 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001649 binop(Iop_Add32,
1650 binop(Iop_Add32,
1651 getIReg(4,base_r),
1652 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001653 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001654 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001655 }
sewardjba89f4c2005-04-07 17:31:27 +00001656 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001657 vassert(0);
1658 }
1659
1660 /* SIB, with 32-bit displacement. Special cases:
1661 -- %esp cannot act as an index value.
1662 If index_r indicates %esp, zero is used for the index.
1663 Denoted value is:
1664 | %index == %ESP
1665 = d32 + %base
1666 | %index != %ESP
1667 = d32 + %base + (%index << scale)
1668 */
1669 case 0x14: {
1670 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001671 UChar scale = toUChar((sib >> 6) & 3);
1672 UChar index_r = toUChar((sib >> 3) & 7);
1673 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001674 UInt d = getUDisp32(delta+1);
1675
1676 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001677 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1678 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001679 *len = 6;
1680 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001681 handleSegOverride(sorb,
1682 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001683 } else {
sewardj2d49b432005-02-01 00:37:06 +00001684 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1685 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001686 *len = 6;
1687 return
sewardj940e8c92004-07-11 16:53:24 +00001688 disAMode_copy2tmp(
1689 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001690 binop(Iop_Add32,
1691 binop(Iop_Add32,
1692 getIReg(4,base_r),
1693 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001694 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001695 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001696 }
sewardjba89f4c2005-04-07 17:31:27 +00001697 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001698 vassert(0);
1699 }
1700
1701 default:
1702 vpanic("disAMode(x86)");
1703 return 0; /*notreached*/
1704 }
1705}
1706
1707
1708/* Figure out the number of (insn-stream) bytes constituting the amode
1709 beginning at delta. Is useful for getting hold of literals beyond
1710 the end of the amode before it has been disassembled. */
1711
sewardj52d04912005-07-03 00:52:48 +00001712static UInt lengthAMode ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +00001713{
1714 UChar mod_reg_rm = getIByte(delta); delta++;
1715
1716 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1717 jump table seems a bit excessive.
1718 */
1719 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj9b45b482005-02-07 01:42:18 +00001720 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1721 /* is now XX0XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001722 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1723 switch (mod_reg_rm) {
1724
1725 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1726 case 0x00: case 0x01: case 0x02: case 0x03:
1727 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1728 return 1;
1729
1730 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1731 case 0x08: case 0x09: case 0x0A: case 0x0B:
1732 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1733 return 2;
1734
1735 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1736 case 0x10: case 0x11: case 0x12: case 0x13:
1737 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1738 return 5;
1739
1740 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1741 case 0x18: case 0x19: case 0x1A: case 0x1B:
1742 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1743 return 1;
1744
1745 /* a 32-bit literal address. */
1746 case 0x05: return 5;
1747
1748 /* SIB, no displacement. */
1749 case 0x04: {
1750 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001751 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001752 if (base_r == R_EBP) return 6; else return 2;
1753 }
1754 /* SIB, with 8-bit displacement. */
1755 case 0x0C: return 3;
1756
1757 /* SIB, with 32-bit displacement. */
1758 case 0x14: return 6;
1759
1760 default:
1761 vpanic("lengthAMode");
1762 return 0; /*notreached*/
1763 }
1764}
1765
1766/*------------------------------------------------------------*/
1767/*--- Disassembling common idioms ---*/
1768/*------------------------------------------------------------*/
1769
sewardje87b4842004-07-10 12:23:30 +00001770/* Handle binary integer instructions of the form
1771 op E, G meaning
1772 op reg-or-mem, reg
1773 Is passed the a ptr to the modRM byte, the actual operation, and the
1774 data size. Returns the address advanced completely over this
1775 instruction.
1776
1777 E(src) is reg-or-mem
1778 G(dst) is reg.
1779
1780 If E is reg, --> GET %G, tmp
1781 OP %E, tmp
1782 PUT tmp, %G
1783
1784 If E is mem and OP is not reversible,
1785 --> (getAddr E) -> tmpa
1786 LD (tmpa), tmpa
1787 GET %G, tmp2
1788 OP tmpa, tmp2
1789 PUT tmp2, %G
1790
1791 If E is mem and OP is reversible
1792 --> (getAddr E) -> tmpa
1793 LD (tmpa), tmpa
1794 OP %G, tmpa
1795 PUT tmpa, %G
1796*/
1797static
1798UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001799 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001800 IROp op8,
1801 Bool keep,
1802 Int size,
sewardj52d04912005-07-03 00:52:48 +00001803 Int delta0,
sewardj2d49b432005-02-01 00:37:06 +00001804 HChar* t_x86opc )
sewardje87b4842004-07-10 12:23:30 +00001805{
sewardjc9a43662004-11-30 18:51:59 +00001806 HChar dis_buf[50];
sewardj9334b0f2004-07-10 22:43:54 +00001807 Int len;
sewardje87b4842004-07-10 12:23:30 +00001808 IRType ty = szToITy(size);
1809 IRTemp dst1 = newTemp(ty);
1810 IRTemp src = newTemp(ty);
1811 IRTemp dst0 = newTemp(ty);
1812 UChar rm = getUChar(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001813 IRTemp addr = IRTemp_INVALID;
sewardje87b4842004-07-10 12:23:30 +00001814
sewardj180e8b32004-07-29 01:40:11 +00001815 /* addSubCarry == True indicates the intended operation is
1816 add-with-carry or subtract-with-borrow. */
1817 if (addSubCarry) {
1818 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1819 vassert(keep);
1820 }
1821
sewardje87b4842004-07-10 12:23:30 +00001822 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001823 /* Specially handle XOR reg,reg, because that doesn't really
1824 depend on reg, and doing the obvious thing potentially
1825 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001826 dependency. Ditto SBB reg,reg. */
1827 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1828 && gregOfRM(rm) == eregOfRM(rm)) {
1829 putIReg(size, gregOfRM(rm), mkU(ty,0));
sewardje87b4842004-07-10 12:23:30 +00001830 }
sewardje87b4842004-07-10 12:23:30 +00001831 assign( dst0, getIReg(size,gregOfRM(rm)) );
1832 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00001833
sewardj180e8b32004-07-29 01:40:11 +00001834 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001835 helper_ADC( size, dst1, dst0, src,
1836 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardje87b4842004-07-10 12:23:30 +00001837 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001838 } else
1839 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001840 helper_SBB( size, dst1, dst0, src,
1841 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00001842 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1843 } else {
1844 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001845 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001846 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001847 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001848 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001849 if (keep)
1850 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1851 }
sewardje87b4842004-07-10 12:23:30 +00001852
1853 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1854 nameIReg(size,eregOfRM(rm)),
1855 nameIReg(size,gregOfRM(rm)));
1856 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001857 } else {
sewardj9334b0f2004-07-10 22:43:54 +00001858 /* E refers to memory */
1859 addr = disAMode ( &len, sorb, delta0, dis_buf);
1860 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00001861 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00001862
sewardj180e8b32004-07-29 01:40:11 +00001863 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001864 helper_ADC( size, dst1, dst0, src,
1865 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj9334b0f2004-07-10 22:43:54 +00001866 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001867 } else
1868 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001869 helper_SBB( size, dst1, dst0, src,
1870 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00001871 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1872 } else {
1873 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001874 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001875 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001876 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001877 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001878 if (keep)
1879 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1880 }
sewardj9334b0f2004-07-10 22:43:54 +00001881
sewardje87b4842004-07-10 12:23:30 +00001882 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1883 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00001884 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00001885 }
sewardje87b4842004-07-10 12:23:30 +00001886}
sewardje05c42c2004-07-08 20:25:10 +00001887
1888
1889
1890/* Handle binary integer instructions of the form
1891 op G, E meaning
1892 op reg, reg-or-mem
1893 Is passed the a ptr to the modRM byte, the actual operation, and the
1894 data size. Returns the address advanced completely over this
1895 instruction.
1896
1897 G(src) is reg.
1898 E(dst) is reg-or-mem
1899
1900 If E is reg, --> GET %E, tmp
1901 OP %G, tmp
1902 PUT tmp, %E
1903
1904 If E is mem, --> (getAddr E) -> tmpa
1905 LD (tmpa), tmpv
1906 OP %G, tmpv
1907 ST tmpv, (tmpa)
1908*/
1909static
1910UInt dis_op2_G_E ( UChar sorb,
sewardje9d8a262009-07-01 08:06:34 +00001911 Bool locked,
sewardjcaca9d02004-07-28 07:11:32 +00001912 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00001913 IROp op8,
1914 Bool keep,
1915 Int size,
sewardj52d04912005-07-03 00:52:48 +00001916 Int delta0,
sewardj2d49b432005-02-01 00:37:06 +00001917 HChar* t_x86opc )
sewardje05c42c2004-07-08 20:25:10 +00001918{
sewardjc9a43662004-11-30 18:51:59 +00001919 HChar dis_buf[50];
sewardje87b4842004-07-10 12:23:30 +00001920 Int len;
sewardje05c42c2004-07-08 20:25:10 +00001921 IRType ty = szToITy(size);
1922 IRTemp dst1 = newTemp(ty);
1923 IRTemp src = newTemp(ty);
1924 IRTemp dst0 = newTemp(ty);
1925 UChar rm = getIByte(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001926 IRTemp addr = IRTemp_INVALID;
sewardje05c42c2004-07-08 20:25:10 +00001927
sewardjcaca9d02004-07-28 07:11:32 +00001928 /* addSubCarry == True indicates the intended operation is
1929 add-with-carry or subtract-with-borrow. */
1930 if (addSubCarry) {
1931 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1932 vassert(keep);
1933 }
1934
sewardje05c42c2004-07-08 20:25:10 +00001935 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00001936 /* Specially handle XOR reg,reg, because that doesn't really
1937 depend on reg, and doing the obvious thing potentially
1938 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001939 dependency. Ditto SBB reg,reg.*/
1940 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1941 && gregOfRM(rm) == eregOfRM(rm)) {
1942 putIReg(size, eregOfRM(rm), mkU(ty,0));
sewardje05c42c2004-07-08 20:25:10 +00001943 }
sewardje05c42c2004-07-08 20:25:10 +00001944 assign(dst0, getIReg(size,eregOfRM(rm)));
1945 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001946
sewardjcaca9d02004-07-28 07:11:32 +00001947 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001948 helper_ADC( size, dst1, dst0, src,
1949 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj1813dbe2004-07-28 17:09:04 +00001950 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001951 } else
1952 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001953 helper_SBB( size, dst1, dst0, src,
1954 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardje05c42c2004-07-08 20:25:10 +00001955 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001956 } else {
1957 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00001958 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001959 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001960 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001961 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001962 if (keep)
1963 putIReg(size, eregOfRM(rm), mkexpr(dst1));
1964 }
sewardje05c42c2004-07-08 20:25:10 +00001965
1966 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1967 nameIReg(size,gregOfRM(rm)),
1968 nameIReg(size,eregOfRM(rm)));
1969 return 1+delta0;
1970 }
1971
1972 /* E refers to memory */
1973 {
sewardje87b4842004-07-10 12:23:30 +00001974 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00001975 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00001976 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001977
sewardjcaca9d02004-07-28 07:11:32 +00001978 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001979 if (locked) {
1980 /* cas-style store */
1981 helper_ADC( size, dst1, dst0, src,
1982 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
1983 } else {
1984 /* normal store */
1985 helper_ADC( size, dst1, dst0, src,
1986 /*store*/addr, IRTemp_INVALID, 0 );
1987 }
sewardjcaca9d02004-07-28 07:11:32 +00001988 } else
1989 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001990 if (locked) {
1991 /* cas-style store */
1992 helper_SBB( size, dst1, dst0, src,
1993 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
1994 } else {
1995 /* normal store */
1996 helper_SBB( size, dst1, dst0, src,
1997 /*store*/addr, IRTemp_INVALID, 0 );
1998 }
sewardjcaca9d02004-07-28 07:11:32 +00001999 } else {
2000 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00002001 if (keep) {
2002 if (locked) {
2003 if (0) vex_printf("locked case\n" );
2004 casLE( mkexpr(addr),
2005 mkexpr(dst0)/*expval*/,
2006 mkexpr(dst1)/*newval*/, guest_EIP_curr_instr );
2007 } else {
2008 if (0) vex_printf("nonlocked case\n");
2009 storeLE(mkexpr(addr), mkexpr(dst1));
2010 }
2011 }
sewardj5bd4d162004-11-10 13:02:48 +00002012 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002013 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002014 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002015 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00002016 }
sewardje87b4842004-07-10 12:23:30 +00002017
sewardje05c42c2004-07-08 20:25:10 +00002018 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2019 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00002020 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002021 }
2022}
2023
2024
2025/* Handle move instructions of the form
2026 mov E, G meaning
2027 mov reg-or-mem, reg
2028 Is passed the a ptr to the modRM byte, and the data size. Returns
2029 the address advanced completely over this instruction.
2030
2031 E(src) is reg-or-mem
2032 G(dst) is reg.
2033
2034 If E is reg, --> GET %E, tmpv
2035 PUT tmpv, %G
2036
2037 If E is mem --> (getAddr E) -> tmpa
2038 LD (tmpa), tmpb
2039 PUT tmpb, %G
2040*/
2041static
2042UInt dis_mov_E_G ( UChar sorb,
2043 Int size,
sewardj52d04912005-07-03 00:52:48 +00002044 Int delta0 )
sewardje05c42c2004-07-08 20:25:10 +00002045{
2046 Int len;
2047 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002048 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002049
2050 if (epartIsReg(rm)) {
sewardj7ca37d92004-10-25 02:58:30 +00002051 putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002052 DIP("mov%c %s,%s\n", nameISize(size),
2053 nameIReg(size,eregOfRM(rm)),
2054 nameIReg(size,gregOfRM(rm)));
sewardj7ca37d92004-10-25 02:58:30 +00002055 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002056 }
2057
2058 /* E refers to memory */
2059 {
sewardj940e8c92004-07-11 16:53:24 +00002060 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
2061 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00002062 DIP("mov%c %s,%s\n", nameISize(size),
2063 dis_buf,nameIReg(size,gregOfRM(rm)));
2064 return delta0+len;
2065 }
2066}
2067
2068
2069/* Handle move instructions of the form
2070 mov G, E meaning
2071 mov reg, reg-or-mem
2072 Is passed the a ptr to the modRM byte, and the data size. Returns
2073 the address advanced completely over this instruction.
2074
2075 G(src) is reg.
2076 E(dst) is reg-or-mem
2077
2078 If E is reg, --> GET %G, tmp
2079 PUT tmp, %E
2080
2081 If E is mem, --> (getAddr E) -> tmpa
2082 GET %G, tmpv
2083 ST tmpv, (tmpa)
2084*/
sewardjc9a65702004-07-07 16:32:57 +00002085static
2086UInt dis_mov_G_E ( UChar sorb,
2087 Int size,
sewardj52d04912005-07-03 00:52:48 +00002088 Int delta0 )
sewardjc9a65702004-07-07 16:32:57 +00002089{
sewardje05c42c2004-07-08 20:25:10 +00002090 Int len;
sewardjc9a65702004-07-07 16:32:57 +00002091 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002092 HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00002093
2094 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00002095 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00002096 DIP("mov%c %s,%s\n", nameISize(size),
2097 nameIReg(size,gregOfRM(rm)),
2098 nameIReg(size,eregOfRM(rm)));
2099 return 1+delta0;
2100 }
2101
sewardjc9a65702004-07-07 16:32:57 +00002102 /* E refers to memory */
2103 {
sewardj940e8c92004-07-11 16:53:24 +00002104 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
2105 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00002106 DIP("mov%c %s,%s\n", nameISize(size),
2107 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00002108 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00002109 }
sewardjc9a65702004-07-07 16:32:57 +00002110}
2111
2112
sewardj0611d802004-07-11 02:37:54 +00002113/* op $immediate, AL/AX/EAX. */
2114static
2115UInt dis_op_imm_A ( Int size,
sewardja718d5d2005-04-03 14:59:54 +00002116 Bool carrying,
sewardj0611d802004-07-11 02:37:54 +00002117 IROp op8,
2118 Bool keep,
sewardj52d04912005-07-03 00:52:48 +00002119 Int delta,
sewardj2d49b432005-02-01 00:37:06 +00002120 HChar* t_x86opc )
sewardj0611d802004-07-11 02:37:54 +00002121{
2122 IRType ty = szToITy(size);
2123 IRTemp dst0 = newTemp(ty);
2124 IRTemp src = newTemp(ty);
2125 IRTemp dst1 = newTemp(ty);
2126 UInt lit = getUDisp(size,delta);
2127 assign(dst0, getIReg(size,R_EAX));
2128 assign(src, mkU(ty,lit));
sewardja718d5d2005-04-03 14:59:54 +00002129
2130 if (isAddSub(op8) && !carrying) {
2131 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002132 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardja718d5d2005-04-03 14:59:54 +00002133 }
sewardjb9c5cf62004-08-24 15:10:38 +00002134 else
sewardja718d5d2005-04-03 14:59:54 +00002135 if (isLogic(op8)) {
2136 vassert(!carrying);
2137 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002138 setFlags_DEP1(op8, dst1, ty);
sewardja718d5d2005-04-03 14:59:54 +00002139 }
2140 else
2141 if (op8 == Iop_Add8 && carrying) {
sewardje9d8a262009-07-01 08:06:34 +00002142 helper_ADC( size, dst1, dst0, src,
2143 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardja718d5d2005-04-03 14:59:54 +00002144 }
sewardj2a2ba8b2004-11-08 13:14:06 +00002145 else
sewardj2fbae082005-10-03 02:07:08 +00002146 if (op8 == Iop_Sub8 && carrying) {
sewardje9d8a262009-07-01 08:06:34 +00002147 helper_SBB( size, dst1, dst0, src,
2148 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj2fbae082005-10-03 02:07:08 +00002149 }
2150 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002151 vpanic("dis_op_imm_A(x86,guest)");
sewardj0611d802004-07-11 02:37:54 +00002152
2153 if (keep)
2154 putIReg(size, R_EAX, mkexpr(dst1));
2155
2156 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
2157 lit, nameIReg(size,R_EAX));
2158 return delta+size;
2159}
sewardj9334b0f2004-07-10 22:43:54 +00002160
2161
2162/* Sign- and Zero-extending moves. */
2163static
sewardj52d04912005-07-03 00:52:48 +00002164UInt dis_movx_E_G ( UChar sorb,
2165 Int delta, Int szs, Int szd, Bool sign_extend )
sewardj9334b0f2004-07-10 22:43:54 +00002166{
sewardj9334b0f2004-07-10 22:43:54 +00002167 UChar rm = getIByte(delta);
2168 if (epartIsReg(rm)) {
2169 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00002170 unop(mkWidenOp(szs,szd,sign_extend),
2171 getIReg(szs,eregOfRM(rm))));
sewardj9334b0f2004-07-10 22:43:54 +00002172 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2173 nameISize(szs), nameISize(szd),
2174 nameIReg(szs,eregOfRM(rm)),
2175 nameIReg(szd,gregOfRM(rm)));
2176 return 1+delta;
2177 }
2178
2179 /* E refers to memory */
2180 {
sewardj940e8c92004-07-11 16:53:24 +00002181 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002182 HChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00002183 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj0611d802004-07-11 02:37:54 +00002184
2185 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00002186 unop(mkWidenOp(szs,szd,sign_extend),
sewardj940e8c92004-07-11 16:53:24 +00002187 loadLE(szToITy(szs),mkexpr(addr))));
sewardj9334b0f2004-07-10 22:43:54 +00002188 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2189 nameISize(szs), nameISize(szd),
2190 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00002191 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00002192 }
2193}
2194
sewardj9690d922004-07-14 01:39:17 +00002195
2196/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
2197 16 / 8 bit quantity in the given IRTemp. */
2198static
2199void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2200{
sewardje5427e82004-09-11 19:43:51 +00002201 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2202 IRTemp src64 = newTemp(Ity_I64);
2203 IRTemp dst64 = newTemp(Ity_I64);
sewardj9690d922004-07-14 01:39:17 +00002204 switch (sz) {
sewardje5427e82004-09-11 19:43:51 +00002205 case 4:
sewardj9690d922004-07-14 01:39:17 +00002206 assign( src64, binop(Iop_32HLto64,
sewardje5427e82004-09-11 19:43:51 +00002207 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
sewardj9690d922004-07-14 01:39:17 +00002208 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00002209 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00002210 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2211 break;
sewardje5427e82004-09-11 19:43:51 +00002212 case 2: {
2213 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2214 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2215 assign( src64, unop(widen3264,
2216 binop(Iop_16HLto32,
2217 getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2218 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2219 putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2220 putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2221 break;
sewardj9690d922004-07-14 01:39:17 +00002222 }
sewardj4e82db72004-10-16 11:32:15 +00002223 case 1: {
2224 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2225 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2226 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2227 assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2228 assign( dst64,
2229 binop(op, mkexpr(src64),
2230 unop(widen1632, unop(widen816, mkexpr(t)))) );
2231 putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2232 unop(Iop_64to32,mkexpr(dst64)))) );
2233 putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2234 unop(Iop_64HIto32,mkexpr(dst64)))) );
2235 break;
2236 }
sewardj9690d922004-07-14 01:39:17 +00002237 default: vpanic("codegen_div(x86)");
2238 }
2239}
sewardj41f43bc2004-07-08 14:23:22 +00002240
2241
2242static
sewardje9d8a262009-07-01 08:06:34 +00002243UInt dis_Grp1 ( UChar sorb, Bool locked,
sewardj52d04912005-07-03 00:52:48 +00002244 Int delta, UChar modrm,
sewardj41f43bc2004-07-08 14:23:22 +00002245 Int am_sz, Int d_sz, Int sz, UInt d32 )
2246{
sewardj41f43bc2004-07-08 14:23:22 +00002247 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002248 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002249 IRType ty = szToITy(sz);
2250 IRTemp dst1 = newTemp(ty);
2251 IRTemp src = newTemp(ty);
2252 IRTemp dst0 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002253 IRTemp addr = IRTemp_INVALID;
sewardj66de2272004-07-16 21:19:05 +00002254 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002255 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002256
2257 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002258 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002259 case 2: break; // ADC
2260 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002261 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2262 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardjd51dc812007-03-20 14:18:45 +00002263 /*NOTREACHED*/
sewardj41f43bc2004-07-08 14:23:22 +00002264 default: vpanic("dis_Grp1: unhandled case");
2265 }
sewardj41f43bc2004-07-08 14:23:22 +00002266
2267 if (epartIsReg(modrm)) {
2268 vassert(am_sz == 1);
2269
2270 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002271 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002272
sewardj180e8b32004-07-29 01:40:11 +00002273 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardje9d8a262009-07-01 08:06:34 +00002274 helper_ADC( sz, dst1, dst0, src,
2275 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00002276 } else
2277 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje9d8a262009-07-01 08:06:34 +00002278 helper_SBB( sz, dst1, dst0, src,
2279 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00002280 } else {
2281 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002282 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002283 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002284 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002285 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002286 }
sewardj41f43bc2004-07-08 14:23:22 +00002287
2288 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002289 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002290
2291 delta += (am_sz + d_sz);
2292 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2293 nameIReg(sz,eregOfRM(modrm)));
2294 } else {
sewardje87b4842004-07-10 12:23:30 +00002295 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002296
sewardj940e8c92004-07-11 16:53:24 +00002297 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002298 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002299
sewardj66de2272004-07-16 21:19:05 +00002300 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardje9d8a262009-07-01 08:06:34 +00002301 if (locked) {
2302 /* cas-style store */
2303 helper_ADC( sz, dst1, dst0, src,
2304 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2305 } else {
2306 /* normal store */
2307 helper_ADC( sz, dst1, dst0, src,
2308 /*store*/addr, IRTemp_INVALID, 0 );
2309 }
sewardj3af115f2004-07-14 02:46:52 +00002310 } else
sewardj66de2272004-07-16 21:19:05 +00002311 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje9d8a262009-07-01 08:06:34 +00002312 if (locked) {
2313 /* cas-style store */
2314 helper_SBB( sz, dst1, dst0, src,
2315 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2316 } else {
2317 /* normal store */
2318 helper_SBB( sz, dst1, dst0, src,
2319 /*store*/addr, IRTemp_INVALID, 0 );
2320 }
sewardj3af115f2004-07-14 02:46:52 +00002321 } else {
2322 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00002323 if (gregOfRM(modrm) < 7) {
2324 if (locked) {
2325 casLE( mkexpr(addr), mkexpr(dst0)/*expVal*/,
2326 mkexpr(dst1)/*newVal*/,
2327 guest_EIP_curr_instr );
2328 } else {
2329 storeLE(mkexpr(addr), mkexpr(dst1));
2330 }
2331 }
sewardj5bd4d162004-11-10 13:02:48 +00002332 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002333 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002334 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002335 setFlags_DEP1(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002336 }
sewardj41f43bc2004-07-08 14:23:22 +00002337
sewardj41f43bc2004-07-08 14:23:22 +00002338 delta += (len+d_sz);
2339 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2340 d32, dis_buf);
2341 }
2342 return delta;
2343}
2344
2345
sewardj6d2638e2004-07-15 09:38:27 +00002346/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2347 expression. */
2348
sewardje90ad6a2004-07-10 19:02:10 +00002349static
sewardj52d04912005-07-03 00:52:48 +00002350UInt dis_Grp2 ( UChar sorb,
2351 Int delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002352 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
sewardjd51dc812007-03-20 14:18:45 +00002353 HChar* shift_expr_txt, Bool* decode_OK )
sewardje90ad6a2004-07-10 19:02:10 +00002354{
2355 /* delta on entry points at the modrm byte. */
sewardjc9a43662004-11-30 18:51:59 +00002356 HChar dis_buf[50];
sewardj6d2638e2004-07-15 09:38:27 +00002357 Int len;
sewardj2eef7732005-08-23 15:41:14 +00002358 Bool isShift, isRotate, isRotateC;
sewardj6d2638e2004-07-15 09:38:27 +00002359 IRType ty = szToITy(sz);
2360 IRTemp dst0 = newTemp(ty);
2361 IRTemp dst1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002362 IRTemp addr = IRTemp_INVALID;
sewardje90ad6a2004-07-10 19:02:10 +00002363
sewardjd51dc812007-03-20 14:18:45 +00002364 *decode_OK = True;
2365
sewardje90ad6a2004-07-10 19:02:10 +00002366 vassert(sz == 1 || sz == 2 || sz == 4);
2367
sewardje90ad6a2004-07-10 19:02:10 +00002368 /* Put value to shift/rotate in dst0. */
2369 if (epartIsReg(modrm)) {
2370 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002371 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002372 } else {
sewardj940e8c92004-07-11 16:53:24 +00002373 addr = disAMode ( &len, sorb, delta, dis_buf);
2374 assign(dst0, loadLE(ty,mkexpr(addr)));
2375 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002376 }
2377
2378 isShift = False;
2379 switch (gregOfRM(modrm)) { case 4: case 5: case 7: isShift = True; }
2380
sewardj750f4072004-07-26 22:39:11 +00002381 isRotate = False;
2382 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2383
sewardj2eef7732005-08-23 15:41:14 +00002384 isRotateC = False;
2385 switch (gregOfRM(modrm)) { case 2: case 3: isRotateC = True; }
sewardj9aebb0c2004-10-24 19:20:43 +00002386
sewardjd51dc812007-03-20 14:18:45 +00002387 if (gregOfRM(modrm) == 6) {
2388 *decode_OK = False;
2389 return delta;
2390 }
2391
sewardj2eef7732005-08-23 15:41:14 +00002392 if (!isShift && !isRotate && !isRotateC) {
sewardjd51dc812007-03-20 14:18:45 +00002393 /*NOTREACHED*/
sewardj8c7f1ab2004-07-29 20:31:09 +00002394 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2395 }
2396
sewardj2eef7732005-08-23 15:41:14 +00002397 if (isRotateC) {
2398 /* call a helper; these insns are so ridiculous they do not
2399 deserve better */
2400 Bool left = toBool(gregOfRM(modrm) == 2);
sewardj9aebb0c2004-10-24 19:20:43 +00002401 IRTemp r64 = newTemp(Ity_I64);
sewardjf9655262004-10-31 20:02:16 +00002402 IRExpr** args
2403 = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2404 widenUto32(shift_expr), /* rotate amount */
sewardj2a9ad022004-11-25 02:46:58 +00002405 widenUto32(mk_x86g_calculate_eflags_all()),
sewardjf9655262004-10-31 20:02:16 +00002406 mkU32(sz) );
2407 assign( r64, mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00002408 Ity_I64,
sewardjf9655262004-10-31 20:02:16 +00002409 0/*regparm*/,
sewardj2eef7732005-08-23 15:41:14 +00002410 left ? "x86g_calculate_RCL" : "x86g_calculate_RCR",
2411 left ? &x86g_calculate_RCL : &x86g_calculate_RCR,
sewardj8ea867b2004-10-30 19:03:02 +00002412 args
sewardjf9655262004-10-31 20:02:16 +00002413 )
2414 );
sewardj9aebb0c2004-10-24 19:20:43 +00002415 /* new eflags in hi half r64; new value in lo half r64 */
2416 assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
sewardj2a9ad022004-11-25 02:46:58 +00002417 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002418 stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
2419 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardja3b7e3a2005-04-05 01:54:19 +00002420 /* Set NDEP even though it isn't used. This makes redundant-PUT
2421 elimination of previous stores to this field work better. */
2422 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj9aebb0c2004-10-24 19:20:43 +00002423 }
2424
sewardje90ad6a2004-07-10 19:02:10 +00002425 if (isShift) {
2426
sewardjc22a6fd2004-07-29 23:41:47 +00002427 IRTemp pre32 = newTemp(Ity_I32);
2428 IRTemp res32 = newTemp(Ity_I32);
2429 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002430 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002431 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002432
2433 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002434 case 4: op32 = Iop_Shl32; break;
2435 case 5: op32 = Iop_Shr32; break;
2436 case 7: op32 = Iop_Sar32; break;
sewardjd51dc812007-03-20 14:18:45 +00002437 /*NOTREACHED*/
sewardje90ad6a2004-07-10 19:02:10 +00002438 default: vpanic("dis_Grp2:shift"); break;
2439 }
2440
sewardjc22a6fd2004-07-29 23:41:47 +00002441 /* Widen the value to be shifted to 32 bits, do the shift, and
2442 narrow back down. This seems surprisingly long-winded, but
2443 unfortunately the Intel semantics requires that 8/16-bit
2444 shifts give defined results for shift values all the way up
2445 to 31, and this seems the simplest way to do it. It has the
2446 advantage that the only IR level shifts generated are of 32
2447 bit values, and the shift amount is guaranteed to be in the
2448 range 0 .. 31, thereby observing the IR semantics requiring
2449 all shift values to be in the range 0 .. 2^word_size-1. */
2450
2451 /* shift_amt = shift_expr & 31, regardless of operation size */
2452 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2453
2454 /* suitably widen the value to be shifted to 32 bits. */
2455 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2456 : widenUto32(mkexpr(dst0)) );
2457
2458 /* res32 = pre32 `shift` shift_amt */
2459 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2460
2461 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2462 assign( res32ss,
2463 binop(op32,
2464 mkexpr(pre32),
2465 binop(Iop_And8,
2466 binop(Iop_Sub8,
2467 mkexpr(shift_amt), mkU8(1)),
2468 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002469
2470 /* Build the flags thunk. */
sewardj2a2ba8b2004-11-08 13:14:06 +00002471 setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
sewardjc22a6fd2004-07-29 23:41:47 +00002472
2473 /* Narrow the result back down. */
2474 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002475
sewardj1813dbe2004-07-28 17:09:04 +00002476 } /* if (isShift) */
2477
2478 else
sewardj750f4072004-07-26 22:39:11 +00002479 if (isRotate) {
sewardj7ebbdae2004-08-26 12:30:48 +00002480 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj2d49b432005-02-01 00:37:06 +00002481 Bool left = toBool(gregOfRM(modrm) == 0);
sewardj7ebbdae2004-08-26 12:30:48 +00002482 IRTemp rot_amt = newTemp(Ity_I8);
2483 IRTemp rot_amt32 = newTemp(Ity_I8);
2484 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002485
2486 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002487 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2488 expressions never shift beyond the word size and thus remain
2489 well defined. */
sewardj7ebbdae2004-08-26 12:30:48 +00002490 assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2491
2492 if (ty == Ity_I32)
2493 assign(rot_amt, mkexpr(rot_amt32));
2494 else
2495 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
sewardj750f4072004-07-26 22:39:11 +00002496
2497 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002498
sewardj750f4072004-07-26 22:39:11 +00002499 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2500 assign(dst1,
2501 binop( mkSizedOp(ty,Iop_Or8),
2502 binop( mkSizedOp(ty,Iop_Shl8),
2503 mkexpr(dst0),
2504 mkexpr(rot_amt)
2505 ),
2506 binop( mkSizedOp(ty,Iop_Shr8),
2507 mkexpr(dst0),
2508 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2509 )
2510 )
2511 );
sewardj2a9ad022004-11-25 02:46:58 +00002512 ccOp += X86G_CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002513
sewardj1813dbe2004-07-28 17:09:04 +00002514 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002515
sewardj1813dbe2004-07-28 17:09:04 +00002516 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2517 assign(dst1,
2518 binop( mkSizedOp(ty,Iop_Or8),
2519 binop( mkSizedOp(ty,Iop_Shr8),
2520 mkexpr(dst0),
2521 mkexpr(rot_amt)
2522 ),
2523 binop( mkSizedOp(ty,Iop_Shl8),
2524 mkexpr(dst0),
2525 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002526 )
2527 )
2528 );
sewardj2a9ad022004-11-25 02:46:58 +00002529 ccOp += X86G_CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002530
sewardj750f4072004-07-26 22:39:11 +00002531 }
sewardjc22a6fd2004-07-29 23:41:47 +00002532
sewardj1813dbe2004-07-28 17:09:04 +00002533 /* dst1 now holds the rotated value. Build flag thunk. We
2534 need the resulting value for this, and the previous flags.
2535 Except don't set it if the rotate count is zero. */
2536
sewardj2a9ad022004-11-25 02:46:58 +00002537 assign(oldFlags, mk_x86g_calculate_eflags_all());
sewardj1813dbe2004-07-28 17:09:04 +00002538
sewardj2a2ba8b2004-11-08 13:14:06 +00002539 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
sewardj1813dbe2004-07-28 17:09:04 +00002540 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj7ebbdae2004-08-26 12:30:48 +00002541 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002542 IRExpr_Get(OFFB_CC_OP,Ity_I32),
2543 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002544 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj7ebbdae2004-08-26 12:30:48 +00002545 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002546 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +00002547 widenUto32(mkexpr(dst1)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002548 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj7ebbdae2004-08-26 12:30:48 +00002549 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002550 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
2551 mkU32(0))) );
2552 stmt( IRStmt_Put( OFFB_CC_NDEP,
2553 IRExpr_Mux0X( mkexpr(rot_amt32),
2554 IRExpr_Get(OFFB_CC_NDEP,Ity_I32),
sewardj1813dbe2004-07-28 17:09:04 +00002555 mkexpr(oldFlags))) );
2556 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002557
2558 /* Save result, and finish up. */
2559 if (epartIsReg(modrm)) {
2560 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002561 if (vex_traceflags & VEX_TRACE_FE) {
sewardje90ad6a2004-07-10 19:02:10 +00002562 vex_printf("%s%c ",
2563 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002564 if (shift_expr_txt)
2565 vex_printf("%s", shift_expr_txt);
2566 else
2567 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002568 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2569 }
sewardje90ad6a2004-07-10 19:02:10 +00002570 } else {
sewardj940e8c92004-07-11 16:53:24 +00002571 storeLE(mkexpr(addr), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002572 if (vex_traceflags & VEX_TRACE_FE) {
sewardj940e8c92004-07-11 16:53:24 +00002573 vex_printf("%s%c ",
2574 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002575 if (shift_expr_txt)
2576 vex_printf("%s", shift_expr_txt);
2577 else
2578 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002579 vex_printf(", %s\n", dis_buf);
2580 }
sewardje90ad6a2004-07-10 19:02:10 +00002581 }
sewardje90ad6a2004-07-10 19:02:10 +00002582 return delta;
2583}
2584
2585
sewardj490ad382005-03-13 17:25:53 +00002586/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2587static
sewardj52d04912005-07-03 00:52:48 +00002588UInt dis_Grp8_Imm ( UChar sorb,
sewardje9d8a262009-07-01 08:06:34 +00002589 Bool locked,
sewardj52d04912005-07-03 00:52:48 +00002590 Int delta, UChar modrm,
sewardj490ad382005-03-13 17:25:53 +00002591 Int am_sz, Int sz, UInt src_val,
2592 Bool* decode_OK )
2593{
2594 /* src_val denotes a d8.
2595 And delta on entry points at the modrm byte. */
sewardje90ad6a2004-07-10 19:02:10 +00002596
sewardj490ad382005-03-13 17:25:53 +00002597 IRType ty = szToITy(sz);
2598 IRTemp t2 = newTemp(Ity_I32);
2599 IRTemp t2m = newTemp(Ity_I32);
2600 IRTemp t_addr = IRTemp_INVALID;
2601 HChar dis_buf[50];
2602 UInt mask;
sewardjd1061ab2004-07-08 01:45:30 +00002603
sewardj490ad382005-03-13 17:25:53 +00002604 /* we're optimists :-) */
2605 *decode_OK = True;
sewardjd1061ab2004-07-08 01:45:30 +00002606
sewardj490ad382005-03-13 17:25:53 +00002607 /* Limit src_val -- the bit offset -- to something within a word.
2608 The Intel docs say that literal offsets larger than a word are
2609 masked in this way. */
2610 switch (sz) {
2611 case 2: src_val &= 15; break;
2612 case 4: src_val &= 31; break;
2613 default: *decode_OK = False; return delta;
2614 }
sewardjcf780b42004-07-13 18:42:17 +00002615
sewardj490ad382005-03-13 17:25:53 +00002616 /* Invent a mask suitable for the operation. */
2617 switch (gregOfRM(modrm)) {
2618 case 4: /* BT */ mask = 0; break;
2619 case 5: /* BTS */ mask = 1 << src_val; break;
2620 case 6: /* BTR */ mask = ~(1 << src_val); break;
2621 case 7: /* BTC */ mask = 1 << src_val; break;
2622 /* If this needs to be extended, probably simplest to make a
2623 new function to handle the other cases (0 .. 3). The
2624 Intel docs do however not indicate any use for 0 .. 3, so
2625 we don't expect this to happen. */
2626 default: *decode_OK = False; return delta;
2627 }
2628
2629 /* Fetch the value to be tested and modified into t2, which is
2630 32-bits wide regardless of sz. */
2631 if (epartIsReg(modrm)) {
2632 vassert(am_sz == 1);
sewardj5a8334e2005-03-13 19:52:45 +00002633 assign( t2, widenUto32(getIReg(sz, eregOfRM(modrm))) );
sewardj490ad382005-03-13 17:25:53 +00002634 delta += (am_sz + 1);
2635 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2636 src_val, nameIReg(sz,eregOfRM(modrm)));
2637 } else {
2638 Int len;
2639 t_addr = disAMode ( &len, sorb, delta, dis_buf);
2640 delta += (len+1);
2641 assign( t2, widenUto32(loadLE(ty, mkexpr(t_addr))) );
2642 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2643 src_val, dis_buf);
2644 }
2645
sewardj490ad382005-03-13 17:25:53 +00002646 /* Compute the new value into t2m, if non-BT. */
2647 switch (gregOfRM(modrm)) {
2648 case 4: /* BT */
2649 break;
2650 case 5: /* BTS */
2651 assign( t2m, binop(Iop_Or32, mkU32(mask), mkexpr(t2)) );
2652 break;
2653 case 6: /* BTR */
2654 assign( t2m, binop(Iop_And32, mkU32(mask), mkexpr(t2)) );
2655 break;
2656 case 7: /* BTC */
2657 assign( t2m, binop(Iop_Xor32, mkU32(mask), mkexpr(t2)) );
2658 break;
sewardjba89f4c2005-04-07 17:31:27 +00002659 default:
2660 /*NOTREACHED*/ /*the previous switch guards this*/
sewardj490ad382005-03-13 17:25:53 +00002661 vassert(0);
2662 }
2663
sewardje9d8a262009-07-01 08:06:34 +00002664 /* Write the result back, if non-BT. If the CAS fails then we
2665 side-exit from the trace at this point, and so the flag state is
2666 not affected. This is of course as required. */
sewardj490ad382005-03-13 17:25:53 +00002667 if (gregOfRM(modrm) != 4 /* BT */) {
2668 if (epartIsReg(modrm)) {
sewardje9d8a262009-07-01 08:06:34 +00002669 putIReg(sz, eregOfRM(modrm), narrowTo(ty, mkexpr(t2m)));
sewardj490ad382005-03-13 17:25:53 +00002670 } else {
sewardje9d8a262009-07-01 08:06:34 +00002671 if (locked) {
2672 casLE( mkexpr(t_addr),
2673 narrowTo(ty, mkexpr(t2))/*expd*/,
2674 narrowTo(ty, mkexpr(t2m))/*new*/,
2675 guest_EIP_curr_instr );
2676 } else {
2677 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
2678 }
sewardj490ad382005-03-13 17:25:53 +00002679 }
2680 }
2681
sewardje9d8a262009-07-01 08:06:34 +00002682 /* Copy relevant bit from t2 into the carry flag. */
2683 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
2684 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
2685 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2686 stmt( IRStmt_Put(
2687 OFFB_CC_DEP1,
2688 binop(Iop_And32,
2689 binop(Iop_Shr32, mkexpr(t2), mkU8(src_val)),
2690 mkU32(1))
2691 ));
2692 /* Set NDEP even though it isn't used. This makes redundant-PUT
2693 elimination of previous stores to this field work better. */
2694 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
2695
sewardj490ad382005-03-13 17:25:53 +00002696 return delta;
2697}
sewardjcf780b42004-07-13 18:42:17 +00002698
2699
sewardj1813dbe2004-07-28 17:09:04 +00002700/* Signed/unsigned widening multiply. Generate IR to multiply the
2701 value in EAX/AX/AL by the given IRTemp, and park the result in
2702 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002703*/
sewardj1813dbe2004-07-28 17:09:04 +00002704static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj2d49b432005-02-01 00:37:06 +00002705 IRTemp tmp, HChar* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002706{
sewardjcf780b42004-07-13 18:42:17 +00002707 IRType ty = szToITy(sz);
2708 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002709
sewardj1813dbe2004-07-28 17:09:04 +00002710 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002711
2712 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002713 case Ity_I32: {
2714 IRTemp res64 = newTemp(Ity_I64);
sewardj948d48b2004-11-05 19:49:09 +00002715 IRTemp resHi = newTemp(Ity_I32);
2716 IRTemp resLo = newTemp(Ity_I32);
sewardjb81f8b32004-07-30 10:17:50 +00002717 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
sewardj2a9ad022004-11-25 02:46:58 +00002718 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002719 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002720 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002721 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2722 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj948d48b2004-11-05 19:49:09 +00002723 putIReg(4, R_EDX, mkexpr(resHi));
2724 putIReg(4, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002725 break;
2726 }
2727 case Ity_I16: {
2728 IRTemp res32 = newTemp(Ity_I32);
sewardj948d48b2004-11-05 19:49:09 +00002729 IRTemp resHi = newTemp(Ity_I16);
2730 IRTemp resLo = newTemp(Ity_I16);
sewardjb81f8b32004-07-30 10:17:50 +00002731 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
sewardj2a9ad022004-11-25 02:46:58 +00002732 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002733 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002734 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002735 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2736 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj948d48b2004-11-05 19:49:09 +00002737 putIReg(2, R_EDX, mkexpr(resHi));
2738 putIReg(2, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002739 break;
2740 }
2741 case Ity_I8: {
2742 IRTemp res16 = newTemp(Ity_I16);
sewardj948d48b2004-11-05 19:49:09 +00002743 IRTemp resHi = newTemp(Ity_I8);
2744 IRTemp resLo = newTemp(Ity_I8);
sewardjb81f8b32004-07-30 10:17:50 +00002745 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
sewardj2a9ad022004-11-25 02:46:58 +00002746 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002747 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002748 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002749 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2750 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardjb81f8b32004-07-30 10:17:50 +00002751 putIReg(2, R_EAX, mkexpr(res16));
2752 break;
2753 }
2754 default:
2755 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002756 }
sewardj1813dbe2004-07-28 17:09:04 +00002757 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002758}
2759
sewardj940e8c92004-07-11 16:53:24 +00002760
2761/* Group 3 extended opcodes. */
2762static
sewardje9d8a262009-07-01 08:06:34 +00002763UInt dis_Grp3 ( UChar sorb, Bool locked, Int sz, Int delta, Bool* decode_OK )
sewardj940e8c92004-07-11 16:53:24 +00002764{
sewardjc9a43662004-11-30 18:51:59 +00002765 UInt d32;
2766 UChar modrm;
2767 HChar dis_buf[50];
2768 Int len;
sewardjc2ac51e2004-07-12 01:03:26 +00002769 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002770 IRType ty = szToITy(sz);
2771 IRTemp t1 = newTemp(ty);
sewardj940e8c92004-07-11 16:53:24 +00002772 IRTemp dst1, src, dst0;
sewardjd51dc812007-03-20 14:18:45 +00002773
2774 *decode_OK = True; /* may change this later */
2775
sewardj940e8c92004-07-11 16:53:24 +00002776 modrm = getIByte(delta);
sewardje9d8a262009-07-01 08:06:34 +00002777
2778 if (locked && (gregOfRM(modrm) != 2 && gregOfRM(modrm) != 3)) {
2779 /* LOCK prefix only allowed with not and neg subopcodes */
2780 *decode_OK = False;
2781 return delta;
2782 }
2783
sewardj940e8c92004-07-11 16:53:24 +00002784 if (epartIsReg(modrm)) {
2785 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002786 case 0: { /* TEST */
2787 delta++; d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002788 dst1 = newTemp(ty);
2789 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2790 getIReg(sz,eregOfRM(modrm)),
sewardjc2ac51e2004-07-12 01:03:26 +00002791 mkU(ty,d32)));
sewardj5bd4d162004-11-10 13:02:48 +00002792 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002793 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2794 nameIReg(sz, eregOfRM(modrm)));
2795 break;
2796 }
sewardjd51dc812007-03-20 14:18:45 +00002797 case 1: /* UNDEFINED */
2798 /* The Intel docs imply this insn is undefined and binutils
2799 agrees. Unfortunately Core 2 will run it (with who
2800 knows what result?) sandpile.org reckons it's an alias
2801 for case 0. We play safe. */
2802 *decode_OK = False;
2803 break;
sewardj940e8c92004-07-11 16:53:24 +00002804 case 2: /* NOT */
2805 delta++;
2806 putIReg(sz, eregOfRM(modrm),
2807 unop(mkSizedOp(ty,Iop_Not8),
2808 getIReg(sz, eregOfRM(modrm))));
2809 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2810 break;
2811 case 3: /* NEG */
2812 delta++;
2813 dst0 = newTemp(ty);
2814 src = newTemp(ty);
2815 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002816 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002817 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardjeb17e492007-08-25 23:07:44 +00002818 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002819 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002820 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj940e8c92004-07-11 16:53:24 +00002821 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2822 break;
sewardjcf780b42004-07-13 18:42:17 +00002823 case 4: /* MUL (unsigned widening) */
2824 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002825 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002826 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002827 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002828 break;
sewardjcaca9d02004-07-28 07:11:32 +00002829 case 5: /* IMUL (signed widening) */
2830 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002831 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002832 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002833 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002834 break;
sewardj68511542004-07-28 00:15:44 +00002835 case 6: /* DIV */
2836 delta++;
2837 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2838 codegen_div ( sz, t1, False );
2839 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2840 break;
sewardjcaca9d02004-07-28 07:11:32 +00002841 case 7: /* IDIV */
2842 delta++;
2843 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2844 codegen_div ( sz, t1, True );
2845 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2846 break;
sewardj940e8c92004-07-11 16:53:24 +00002847 default:
sewardjd51dc812007-03-20 14:18:45 +00002848 /* This can't happen - gregOfRM should return 0 .. 7 only */
sewardj940e8c92004-07-11 16:53:24 +00002849 vpanic("Grp3(x86)");
2850 }
2851 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002852 addr = disAMode ( &len, sorb, delta, dis_buf );
2853 t1 = newTemp(ty);
2854 delta += len;
2855 assign(t1, loadLE(ty,mkexpr(addr)));
2856 switch (gregOfRM(modrm)) {
2857 case 0: { /* TEST */
2858 d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002859 dst1 = newTemp(ty);
2860 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2861 mkexpr(t1), mkU(ty,d32)));
2862 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002863 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2864 break;
2865 }
sewardjd51dc812007-03-20 14:18:45 +00002866 case 1: /* UNDEFINED */
2867 /* See comment above on R case */
2868 *decode_OK = False;
2869 break;
sewardj78fe7912004-08-20 23:38:07 +00002870 case 2: /* NOT */
sewardje9d8a262009-07-01 08:06:34 +00002871 dst1 = newTemp(ty);
2872 assign(dst1, unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2873 if (locked) {
2874 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2875 guest_EIP_curr_instr );
2876 } else {
2877 storeLE( mkexpr(addr), mkexpr(dst1) );
2878 }
sewardj78fe7912004-08-20 23:38:07 +00002879 DIP("not%c %s\n", nameISize(sz), dis_buf);
2880 break;
sewardj0c12ea82004-07-12 08:18:16 +00002881 case 3: /* NEG */
2882 dst0 = newTemp(ty);
2883 src = newTemp(ty);
2884 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002885 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002886 assign(src, mkexpr(t1));
sewardje9d8a262009-07-01 08:06:34 +00002887 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8),
2888 mkexpr(dst0), mkexpr(src)));
2889 if (locked) {
2890 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2891 guest_EIP_curr_instr );
2892 } else {
2893 storeLE( mkexpr(addr), mkexpr(dst1) );
2894 }
sewardj2a2ba8b2004-11-08 13:14:06 +00002895 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj0c12ea82004-07-12 08:18:16 +00002896 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2897 break;
sewardj1813dbe2004-07-28 17:09:04 +00002898 case 4: /* MUL */
2899 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2900 break;
2901 case 5: /* IMUL */
2902 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2903 break;
sewardj9690d922004-07-14 01:39:17 +00002904 case 6: /* DIV */
2905 codegen_div ( sz, t1, False );
2906 DIP("div%c %s\n", nameISize(sz), dis_buf);
2907 break;
sewardj1813dbe2004-07-28 17:09:04 +00002908 case 7: /* IDIV */
2909 codegen_div ( sz, t1, True );
2910 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2911 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002912 default:
sewardjd51dc812007-03-20 14:18:45 +00002913 /* This can't happen - gregOfRM should return 0 .. 7 only */
sewardjc2ac51e2004-07-12 01:03:26 +00002914 vpanic("Grp3(x86)");
2915 }
sewardj940e8c92004-07-11 16:53:24 +00002916 }
2917 return delta;
2918}
2919
2920
sewardjc2ac51e2004-07-12 01:03:26 +00002921/* Group 4 extended opcodes. */
2922static
sewardje9d8a262009-07-01 08:06:34 +00002923UInt dis_Grp4 ( UChar sorb, Bool locked, Int delta, Bool* decode_OK )
sewardjc2ac51e2004-07-12 01:03:26 +00002924{
sewardjc9a43662004-11-30 18:51:59 +00002925 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00002926 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00002927 HChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002928 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00002929 IRTemp t1 = newTemp(ty);
2930 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002931
sewardjd51dc812007-03-20 14:18:45 +00002932 *decode_OK = True;
2933
sewardjc2ac51e2004-07-12 01:03:26 +00002934 modrm = getIByte(delta);
sewardje9d8a262009-07-01 08:06:34 +00002935
2936 if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
2937 /* LOCK prefix only allowed with inc and dec subopcodes */
2938 *decode_OK = False;
2939 return delta;
2940 }
2941
sewardjc2ac51e2004-07-12 01:03:26 +00002942 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002943 assign(t1, getIReg(1, eregOfRM(modrm)));
2944 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00002945 case 0: /* INC */
2946 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2947 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2948 setFlags_INC_DEC( True, t2, ty );
2949 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002950 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00002951 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2952 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2953 setFlags_INC_DEC( False, t2, ty );
2954 break;
2955 default:
sewardjd51dc812007-03-20 14:18:45 +00002956 *decode_OK = False;
2957 return delta;
sewardjc2ac51e2004-07-12 01:03:26 +00002958 }
2959 delta++;
2960 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
2961 nameIReg(1, eregOfRM(modrm)));
2962 } else {
sewardj7ed22952004-07-29 00:09:58 +00002963 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
2964 assign( t1, loadLE(ty, mkexpr(addr)) );
2965 switch (gregOfRM(modrm)) {
sewardj588ea762004-09-10 18:56:32 +00002966 case 0: /* INC */
2967 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardje9d8a262009-07-01 08:06:34 +00002968 if (locked) {
2969 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
2970 guest_EIP_curr_instr );
2971 } else {
2972 storeLE( mkexpr(addr), mkexpr(t2) );
2973 }
sewardj588ea762004-09-10 18:56:32 +00002974 setFlags_INC_DEC( True, t2, ty );
2975 break;
sewardj7ed22952004-07-29 00:09:58 +00002976 case 1: /* DEC */
2977 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardje9d8a262009-07-01 08:06:34 +00002978 if (locked) {
2979 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
2980 guest_EIP_curr_instr );
2981 } else {
2982 storeLE( mkexpr(addr), mkexpr(t2) );
2983 }
sewardj7ed22952004-07-29 00:09:58 +00002984 setFlags_INC_DEC( False, t2, ty );
2985 break;
2986 default:
sewardjd51dc812007-03-20 14:18:45 +00002987 *decode_OK = False;
2988 return delta;
sewardj7ed22952004-07-29 00:09:58 +00002989 }
2990 delta += alen;
2991 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00002992 }
2993 return delta;
2994}
sewardj0611d802004-07-11 02:37:54 +00002995
2996
2997/* Group 5 extended opcodes. */
2998static
sewardje9d8a262009-07-01 08:06:34 +00002999UInt dis_Grp5 ( UChar sorb, Bool locked, Int sz, Int delta,
sewardjd51dc812007-03-20 14:18:45 +00003000 DisResult* dres, Bool* decode_OK )
sewardj0611d802004-07-11 02:37:54 +00003001{
3002 Int len;
3003 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00003004 HChar dis_buf[50];
sewardj92d168d2004-11-15 14:22:12 +00003005 IRTemp addr = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00003006 IRType ty = szToITy(sz);
3007 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00003008 IRTemp t2 = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00003009
sewardjd51dc812007-03-20 14:18:45 +00003010 *decode_OK = True;
3011
sewardj0611d802004-07-11 02:37:54 +00003012 modrm = getIByte(delta);
sewardje9d8a262009-07-01 08:06:34 +00003013
3014 if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
3015 /* LOCK prefix only allowed with inc and dec subopcodes */
3016 *decode_OK = False;
3017 return delta;
3018 }
3019
sewardj0611d802004-07-11 02:37:54 +00003020 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00003021 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00003022 switch (gregOfRM(modrm)) {
sewardj59ff5d42005-10-05 10:39:58 +00003023 case 0: /* INC */
3024 vassert(sz == 2 || sz == 4);
3025 t2 = newTemp(ty);
3026 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3027 mkexpr(t1), mkU(ty,1)));
3028 setFlags_INC_DEC( True, t2, ty );
3029 putIReg(sz,eregOfRM(modrm),mkexpr(t2));
3030 break;
3031 case 1: /* DEC */
3032 vassert(sz == 2 || sz == 4);
3033 t2 = newTemp(ty);
3034 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3035 mkexpr(t1), mkU(ty,1)));
3036 setFlags_INC_DEC( False, t2, ty );
3037 putIReg(sz,eregOfRM(modrm),mkexpr(t2));
3038 break;
sewardjc2ac51e2004-07-12 01:03:26 +00003039 case 2: /* call Ev */
3040 vassert(sz == 4);
3041 t2 = newTemp(Ity_I32);
3042 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3043 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003044 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+1));
sewardj5bd4d162004-11-10 13:02:48 +00003045 jmp_treg(Ijk_Call,t1);
sewardj9e6491a2005-07-02 19:24:10 +00003046 dres->whatNext = Dis_StopHere;
sewardjc2ac51e2004-07-12 01:03:26 +00003047 break;
sewardj0611d802004-07-11 02:37:54 +00003048 case 4: /* jmp Ev */
3049 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00003050 jmp_treg(Ijk_Boring,t1);
sewardj9e6491a2005-07-02 19:24:10 +00003051 dres->whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +00003052 break;
sewardj28905822006-11-18 22:56:46 +00003053 case 6: /* PUSH Ev */
3054 vassert(sz == 4 || sz == 2);
3055 t2 = newTemp(Ity_I32);
3056 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3057 putIReg(4, R_ESP, mkexpr(t2) );
3058 storeLE( mkexpr(t2), mkexpr(t1) );
3059 break;
sewardj0611d802004-07-11 02:37:54 +00003060 default:
sewardjd51dc812007-03-20 14:18:45 +00003061 *decode_OK = False;
3062 return delta;
sewardj0611d802004-07-11 02:37:54 +00003063 }
3064 delta++;
3065 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3066 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
3067 } else {
3068 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00003069 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00003070 switch (gregOfRM(modrm)) {
3071 case 0: /* INC */
3072 t2 = newTemp(ty);
3073 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3074 mkexpr(t1), mkU(ty,1)));
sewardje9d8a262009-07-01 08:06:34 +00003075 if (locked) {
3076 casLE( mkexpr(addr),
3077 mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3078 } else {
3079 storeLE(mkexpr(addr),mkexpr(t2));
3080 }
sewardj0611d802004-07-11 02:37:54 +00003081 setFlags_INC_DEC( True, t2, ty );
sewardj0611d802004-07-11 02:37:54 +00003082 break;
sewardjc2ac51e2004-07-12 01:03:26 +00003083 case 1: /* DEC */
3084 t2 = newTemp(ty);
3085 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3086 mkexpr(t1), mkU(ty,1)));
sewardje9d8a262009-07-01 08:06:34 +00003087 if (locked) {
3088 casLE( mkexpr(addr),
3089 mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3090 } else {
3091 storeLE(mkexpr(addr),mkexpr(t2));
3092 }
sewardjc2ac51e2004-07-12 01:03:26 +00003093 setFlags_INC_DEC( False, t2, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00003094 break;
sewardj77b86be2004-07-11 13:28:24 +00003095 case 2: /* call Ev */
3096 vassert(sz == 4);
3097 t2 = newTemp(Ity_I32);
3098 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3099 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003100 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+len));
sewardj5bd4d162004-11-10 13:02:48 +00003101 jmp_treg(Ijk_Call,t1);
sewardj9e6491a2005-07-02 19:24:10 +00003102 dres->whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00003103 break;
3104 case 4: /* JMP Ev */
3105 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00003106 jmp_treg(Ijk_Boring,t1);
sewardj9e6491a2005-07-02 19:24:10 +00003107 dres->whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00003108 break;
sewardj0c12ea82004-07-12 08:18:16 +00003109 case 6: /* PUSH Ev */
3110 vassert(sz == 4 || sz == 2);
3111 t2 = newTemp(Ity_I32);
3112 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3113 putIReg(4, R_ESP, mkexpr(t2) );
sewardj5bd4d162004-11-10 13:02:48 +00003114 storeLE( mkexpr(t2), mkexpr(t1) );
sewardj0c12ea82004-07-12 08:18:16 +00003115 break;
sewardj0611d802004-07-11 02:37:54 +00003116 default:
sewardjd51dc812007-03-20 14:18:45 +00003117 *decode_OK = False;
3118 return delta;
sewardj0611d802004-07-11 02:37:54 +00003119 }
3120 delta += len;
3121 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3122 nameISize(sz), dis_buf);
3123 }
3124 return delta;
3125}
3126
sewardj464efa42004-11-19 22:17:29 +00003127
sewardj64e1d652004-07-12 14:00:46 +00003128/*------------------------------------------------------------*/
3129/*--- Disassembling string ops (including REP prefixes) ---*/
3130/*------------------------------------------------------------*/
3131
3132/* Code shared by all the string ops */
3133static
3134void dis_string_op_increment(Int sz, Int t_inc)
3135{
3136 if (sz == 4 || sz == 2) {
3137 assign( t_inc,
3138 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00003139 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00003140 } else {
3141 assign( t_inc,
3142 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
3143 }
3144}
3145
sewardj64e1d652004-07-12 14:00:46 +00003146static
3147void dis_string_op( void (*dis_OP)( Int, IRTemp ),
sewardj2d49b432005-02-01 00:37:06 +00003148 Int sz, HChar* name, UChar sorb )
sewardj64e1d652004-07-12 14:00:46 +00003149{
3150 IRTemp t_inc = newTemp(Ity_I32);
sewardj9c3b25a2007-04-05 15:06:56 +00003151 vassert(sorb == 0); /* hmm. so what was the point of passing it in? */
sewardj64e1d652004-07-12 14:00:46 +00003152 dis_string_op_increment(sz, t_inc);
3153 dis_OP( sz, t_inc );
3154 DIP("%s%c\n", name, nameISize(sz));
3155}
sewardj64e1d652004-07-12 14:00:46 +00003156
3157static
3158void dis_MOVS ( Int sz, IRTemp t_inc )
3159{
3160 IRType ty = szToITy(sz);
sewardj64e1d652004-07-12 14:00:46 +00003161 IRTemp td = newTemp(Ity_I32); /* EDI */
3162 IRTemp ts = newTemp(Ity_I32); /* ESI */
3163
sewardj64e1d652004-07-12 14:00:46 +00003164 assign( td, getIReg(4, R_EDI) );
3165 assign( ts, getIReg(4, R_ESI) );
3166
sewardj64e1d652004-07-12 14:00:46 +00003167 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3168
sewardj64e1d652004-07-12 14:00:46 +00003169 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3170 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3171}
3172
sewardj10ca4eb2005-05-30 11:19:54 +00003173static
3174void dis_LODS ( Int sz, IRTemp t_inc )
3175{
3176 IRType ty = szToITy(sz);
3177 IRTemp ts = newTemp(Ity_I32); /* ESI */
3178
3179 assign( ts, getIReg(4, R_ESI) );
3180
3181 putIReg( sz, R_EAX, loadLE(ty, mkexpr(ts)) );
3182
3183 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3184}
sewardj64e1d652004-07-12 14:00:46 +00003185
3186static
3187void dis_STOS ( Int sz, IRTemp t_inc )
3188{
3189 IRType ty = szToITy(sz);
3190 IRTemp ta = newTemp(ty); /* EAX */
3191 IRTemp td = newTemp(Ity_I32); /* EDI */
3192
sewardj64e1d652004-07-12 14:00:46 +00003193 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003194 assign( td, getIReg(4, R_EDI) );
3195
sewardj6d2638e2004-07-15 09:38:27 +00003196 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00003197
sewardj64e1d652004-07-12 14:00:46 +00003198 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3199}
3200
3201static
3202void dis_CMPS ( Int sz, IRTemp t_inc )
3203{
3204 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00003205 IRTemp tdv = newTemp(ty); /* (EDI) */
3206 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj64e1d652004-07-12 14:00:46 +00003207 IRTemp td = newTemp(Ity_I32); /* EDI */
3208 IRTemp ts = newTemp(Ity_I32); /* ESI */
3209
sewardj64e1d652004-07-12 14:00:46 +00003210 assign( td, getIReg(4, R_EDI) );
sewardj64e1d652004-07-12 14:00:46 +00003211 assign( ts, getIReg(4, R_ESI) );
3212
sewardj64e1d652004-07-12 14:00:46 +00003213 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardjb9c5cf62004-08-24 15:10:38 +00003214 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00003215
sewardj2a2ba8b2004-11-08 13:14:06 +00003216 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003217
sewardj64e1d652004-07-12 14:00:46 +00003218 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
sewardj64e1d652004-07-12 14:00:46 +00003219 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3220}
3221
sewardj64e1d652004-07-12 14:00:46 +00003222static
3223void dis_SCAS ( Int sz, IRTemp t_inc )
3224{
3225 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00003226 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00003227 IRTemp td = newTemp(Ity_I32); /* EDI */
3228 IRTemp tdv = newTemp(ty); /* (EDI) */
3229
sewardjb9c5cf62004-08-24 15:10:38 +00003230 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003231 assign( td, getIReg(4, R_EDI) );
3232
sewardj64e1d652004-07-12 14:00:46 +00003233 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00003234 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003235
sewardj64e1d652004-07-12 14:00:46 +00003236 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3237}
sewardj82292882004-07-27 00:15:59 +00003238
sewardj64e1d652004-07-12 14:00:46 +00003239
3240/* Wrap the appropriate string op inside a REP/REPE/REPNE.
3241 We assume the insn is the last one in the basic block, and so emit a jump
3242 to the next insn, rather than just falling through. */
3243static
sewardj2a9ad022004-11-25 02:46:58 +00003244void dis_REP_op ( X86Condcode cond,
sewardj64e1d652004-07-12 14:00:46 +00003245 void (*dis_OP)(Int, IRTemp),
sewardj2d49b432005-02-01 00:37:06 +00003246 Int sz, Addr32 eip, Addr32 eip_next, HChar* name )
sewardj64e1d652004-07-12 14:00:46 +00003247{
3248 IRTemp t_inc = newTemp(Ity_I32);
3249 IRTemp tc = newTemp(Ity_I32); /* ECX */
3250
sewardj64e1d652004-07-12 14:00:46 +00003251 assign( tc, getIReg(4,R_ECX) );
3252
sewardj64e1d652004-07-12 14:00:46 +00003253 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +00003254 Ijk_Boring,
sewardj64e1d652004-07-12 14:00:46 +00003255 IRConst_U32(eip_next) ) );
3256
sewardj64e1d652004-07-12 14:00:46 +00003257 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
3258
3259 dis_string_op_increment(sz, t_inc);
3260 dis_OP (sz, t_inc);
3261
sewardj2a9ad022004-11-25 02:46:58 +00003262 if (cond == X86CondAlways) {
sewardj78c19df2004-07-12 22:49:27 +00003263 jmp_lit(Ijk_Boring,eip);
sewardj64e1d652004-07-12 14:00:46 +00003264 } else {
sewardj2a9ad022004-11-25 02:46:58 +00003265 stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
sewardj893aada2004-11-29 19:57:54 +00003266 Ijk_Boring,
sewardj5bd4d162004-11-10 13:02:48 +00003267 IRConst_U32(eip) ) );
sewardj78c19df2004-07-12 22:49:27 +00003268 jmp_lit(Ijk_Boring,eip_next);
sewardj64e1d652004-07-12 14:00:46 +00003269 }
3270 DIP("%s%c\n", name, nameISize(sz));
3271}
3272
sewardj464efa42004-11-19 22:17:29 +00003273
sewardj64e1d652004-07-12 14:00:46 +00003274/*------------------------------------------------------------*/
3275/*--- Arithmetic, etc. ---*/
3276/*------------------------------------------------------------*/
3277
sewardj2a2ba8b2004-11-08 13:14:06 +00003278/* IMUL E, G. Supplied eip points to the modR/M byte. */
sewardjcf780b42004-07-13 18:42:17 +00003279static
3280UInt dis_mul_E_G ( UChar sorb,
3281 Int size,
sewardj52d04912005-07-03 00:52:48 +00003282 Int delta0 )
sewardjcf780b42004-07-13 18:42:17 +00003283{
sewardj71a65362004-07-28 01:48:34 +00003284 Int alen;
sewardjc9a43662004-11-30 18:51:59 +00003285 HChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00003286 UChar rm = getIByte(delta0);
3287 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00003288 IRTemp te = newTemp(ty);
3289 IRTemp tg = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003290 IRTemp resLo = newTemp(ty);
sewardj71a65362004-07-28 01:48:34 +00003291
sewardj948d48b2004-11-05 19:49:09 +00003292 assign( tg, getIReg(size, gregOfRM(rm)) );
sewardjcf780b42004-07-13 18:42:17 +00003293 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00003294 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj948d48b2004-11-05 19:49:09 +00003295 } else {
3296 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3297 assign( te, loadLE(ty,mkexpr(addr)) );
3298 }
sewardjcf780b42004-07-13 18:42:17 +00003299
sewardj2a9ad022004-11-25 02:46:58 +00003300 setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003301
sewardj2a2ba8b2004-11-08 13:14:06 +00003302 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
sewardj948d48b2004-11-05 19:49:09 +00003303
3304 putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3305
3306 if (epartIsReg(rm)) {
sewardj2a2ba8b2004-11-08 13:14:06 +00003307 DIP("imul%c %s, %s\n", nameISize(size),
3308 nameIReg(size,eregOfRM(rm)),
3309 nameIReg(size,gregOfRM(rm)));
sewardjcf780b42004-07-13 18:42:17 +00003310 return 1+delta0;
3311 } else {
sewardj2a2ba8b2004-11-08 13:14:06 +00003312 DIP("imul%c %s, %s\n", nameISize(size),
3313 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00003314 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00003315 }
3316}
3317
3318
sewardj1813dbe2004-07-28 17:09:04 +00003319/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
3320static
3321UInt dis_imul_I_E_G ( UChar sorb,
3322 Int size,
sewardj52d04912005-07-03 00:52:48 +00003323 Int delta,
sewardj1813dbe2004-07-28 17:09:04 +00003324 Int litsize )
3325{
sewardj883b00b2004-09-11 09:30:24 +00003326 Int d32, alen;
sewardjc9a43662004-11-30 18:51:59 +00003327 HChar dis_buf[50];
sewardjb81f8b32004-07-30 10:17:50 +00003328 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00003329 IRType ty = szToITy(size);
3330 IRTemp te = newTemp(ty);
3331 IRTemp tl = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003332 IRTemp resLo = newTemp(ty);
sewardj1813dbe2004-07-28 17:09:04 +00003333
sewardjb81f8b32004-07-30 10:17:50 +00003334 vassert(size == 1 || size == 2 || size == 4);
3335
sewardj1813dbe2004-07-28 17:09:04 +00003336 if (epartIsReg(rm)) {
3337 assign(te, getIReg(size, eregOfRM(rm)));
3338 delta++;
3339 } else {
sewardj883b00b2004-09-11 09:30:24 +00003340 IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3341 assign(te, loadLE(ty, mkexpr(addr)));
3342 delta += alen;
sewardj1813dbe2004-07-28 17:09:04 +00003343 }
3344 d32 = getSDisp(litsize,delta);
3345 delta += litsize;
3346
sewardjb81f8b32004-07-30 10:17:50 +00003347 if (size == 1) d32 &= 0xFF;
3348 if (size == 2) d32 &= 0xFFFF;
3349
sewardj1813dbe2004-07-28 17:09:04 +00003350 assign(tl, mkU(ty,d32));
sewardj948d48b2004-11-05 19:49:09 +00003351
sewardj2a2ba8b2004-11-08 13:14:06 +00003352 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
sewardj948d48b2004-11-05 19:49:09 +00003353
sewardj2a9ad022004-11-25 02:46:58 +00003354 setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003355
3356 putIReg(size, gregOfRM(rm), mkexpr(resLo));
sewardj1813dbe2004-07-28 17:09:04 +00003357
3358 DIP("imul %d, %s, %s\n", d32,
3359 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3360 nameIReg(size,gregOfRM(rm)) );
3361 return delta;
sewardj948d48b2004-11-05 19:49:09 +00003362}
sewardj1813dbe2004-07-28 17:09:04 +00003363
3364
sewardjd1725d12004-08-12 20:46:53 +00003365/*------------------------------------------------------------*/
sewardj464efa42004-11-19 22:17:29 +00003366/*--- ---*/
3367/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
3368/*--- ---*/
sewardjd1725d12004-08-12 20:46:53 +00003369/*------------------------------------------------------------*/
3370
sewardj207557a2004-08-27 12:00:18 +00003371/* --- Helper functions for dealing with the register stack. --- */
3372
sewardj893aada2004-11-29 19:57:54 +00003373/* --- Set the emulation-warning pseudo-register. --- */
3374
3375static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3376{
sewardjdd40fdf2006-12-24 02:20:24 +00003377 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj893aada2004-11-29 19:57:54 +00003378 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3379}
3380
sewardj17442fe2004-09-20 14:54:28 +00003381/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
sewardj207557a2004-08-27 12:00:18 +00003382
sewardj17442fe2004-09-20 14:54:28 +00003383static IRExpr* mkQNaN64 ( void )
sewardj207557a2004-08-27 12:00:18 +00003384{
sewardj17442fe2004-09-20 14:54:28 +00003385 /* QNaN is 0 2047 1 0(51times)
3386 == 0b 11111111111b 1 0(51times)
3387 == 0x7FF8 0000 0000 0000
3388 */
3389 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
sewardj207557a2004-08-27 12:00:18 +00003390}
3391
sewardj893aada2004-11-29 19:57:54 +00003392/* --------- Get/put the top-of-stack pointer. --------- */
sewardjd1725d12004-08-12 20:46:53 +00003393
3394static IRExpr* get_ftop ( void )
3395{
3396 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3397}
3398
sewardj207557a2004-08-27 12:00:18 +00003399static void put_ftop ( IRExpr* e )
sewardjd1725d12004-08-12 20:46:53 +00003400{
sewardjdd40fdf2006-12-24 02:20:24 +00003401 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj207557a2004-08-27 12:00:18 +00003402 stmt( IRStmt_Put( OFFB_FTOP, e ) );
sewardjd1725d12004-08-12 20:46:53 +00003403}
3404
sewardj893aada2004-11-29 19:57:54 +00003405/* --------- Get/put the C3210 bits. --------- */
sewardjbdc7d212004-09-09 02:46:40 +00003406
sewardjc4be80c2004-09-10 16:17:45 +00003407static IRExpr* get_C3210 ( void )
sewardjbdc7d212004-09-09 02:46:40 +00003408{
sewardjc4be80c2004-09-10 16:17:45 +00003409 return IRExpr_Get( OFFB_FC3210, Ity_I32 );
sewardjbdc7d212004-09-09 02:46:40 +00003410}
3411
sewardjc4be80c2004-09-10 16:17:45 +00003412static void put_C3210 ( IRExpr* e )
sewardjbdc7d212004-09-09 02:46:40 +00003413{
sewardjc4be80c2004-09-10 16:17:45 +00003414 stmt( IRStmt_Put( OFFB_FC3210, e ) );
sewardjbdc7d212004-09-09 02:46:40 +00003415}
sewardjd1725d12004-08-12 20:46:53 +00003416
sewardj893aada2004-11-29 19:57:54 +00003417/* --------- Get/put the FPU rounding mode. --------- */
sewardjd01a9632004-11-30 13:18:37 +00003418static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
sewardj8f3debf2004-09-08 23:42:23 +00003419{
sewardjd01a9632004-11-30 13:18:37 +00003420 return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
sewardj8f3debf2004-09-08 23:42:23 +00003421}
3422
sewardjd01a9632004-11-30 13:18:37 +00003423static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
sewardj8f3debf2004-09-08 23:42:23 +00003424{
sewardjd01a9632004-11-30 13:18:37 +00003425 stmt( IRStmt_Put( OFFB_FPROUND, e ) );
sewardj8f3debf2004-09-08 23:42:23 +00003426}
3427
3428
sewardj893aada2004-11-29 19:57:54 +00003429/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
sewardj8f3debf2004-09-08 23:42:23 +00003430/* Produces a value in 0 .. 3, which is encoded as per the type
sewardjd01a9632004-11-30 13:18:37 +00003431 IRRoundingMode. Since the guest_FPROUND value is also encoded as
3432 per IRRoundingMode, we merely need to get it and mask it for
3433 safety.
sewardj8f3debf2004-09-08 23:42:23 +00003434*/
3435static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3436{
sewardjd01a9632004-11-30 13:18:37 +00003437 return binop( Iop_And32, get_fpround(), mkU32(3) );
sewardj8f3debf2004-09-08 23:42:23 +00003438}
3439
sewardjf1b5b1a2006-02-03 22:54:17 +00003440static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
3441{
3442 return mkU32(Irrm_NEAREST);
3443}
3444
sewardj8f3debf2004-09-08 23:42:23 +00003445
sewardj207557a2004-08-27 12:00:18 +00003446/* --------- Get/set FP register tag bytes. --------- */
3447
sewardj207557a2004-08-27 12:00:18 +00003448/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3449
3450static void put_ST_TAG ( Int i, IRExpr* value )
3451{
sewardjdd40fdf2006-12-24 02:20:24 +00003452 IRRegArray* descr;
3453 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_I8);
3454 descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003455 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003456}
3457
3458/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
sewardjdb199622004-09-06 23:19:03 +00003459 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
sewardj207557a2004-08-27 12:00:18 +00003460
3461static IRExpr* get_ST_TAG ( Int i )
3462{
sewardjdd40fdf2006-12-24 02:20:24 +00003463 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003464 return IRExpr_GetI( descr, get_ftop(), i );
sewardj207557a2004-08-27 12:00:18 +00003465}
3466
3467
3468/* --------- Get/set FP registers. --------- */
3469
sewardj2d3f77c2004-09-22 23:49:09 +00003470/* Given i, and some expression e, emit 'ST(i) = e' and set the
3471 register's tag to indicate the register is full. The previous
3472 state of the register is not checked. */
sewardj207557a2004-08-27 12:00:18 +00003473
3474static void put_ST_UNCHECKED ( Int i, IRExpr* value )
sewardjd1725d12004-08-12 20:46:53 +00003475{
sewardjdd40fdf2006-12-24 02:20:24 +00003476 IRRegArray* descr;
3477 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_F64);
3478 descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003479 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003480 /* Mark the register as in-use. */
3481 put_ST_TAG(i, mkU8(1));
sewardjd1725d12004-08-12 20:46:53 +00003482}
3483
sewardj207557a2004-08-27 12:00:18 +00003484/* Given i, and some expression e, emit
3485 ST(i) = is_full(i) ? NaN : e
3486 and set the tag accordingly.
3487*/
3488
3489static void put_ST ( Int i, IRExpr* value )
3490{
3491 put_ST_UNCHECKED( i,
sewardjdb199622004-09-06 23:19:03 +00003492 IRExpr_Mux0X( get_ST_TAG(i),
3493 /* 0 means empty */
3494 value,
3495 /* non-0 means full */
sewardj17442fe2004-09-20 14:54:28 +00003496 mkQNaN64()
sewardj207557a2004-08-27 12:00:18 +00003497 )
3498 );
3499}
3500
3501
sewardjd1725d12004-08-12 20:46:53 +00003502/* Given i, generate an expression yielding 'ST(i)'. */
3503
sewardj207557a2004-08-27 12:00:18 +00003504static IRExpr* get_ST_UNCHECKED ( Int i )
sewardjd1725d12004-08-12 20:46:53 +00003505{
sewardjdd40fdf2006-12-24 02:20:24 +00003506 IRRegArray* descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003507 return IRExpr_GetI( descr, get_ftop(), i );
sewardjd1725d12004-08-12 20:46:53 +00003508}
3509
sewardjc4be80c2004-09-10 16:17:45 +00003510
sewardj207557a2004-08-27 12:00:18 +00003511/* Given i, generate an expression yielding
3512 is_full(i) ? ST(i) : NaN
3513*/
3514
3515static IRExpr* get_ST ( Int i )
3516{
3517 return
3518 IRExpr_Mux0X( get_ST_TAG(i),
3519 /* 0 means empty */
sewardj17442fe2004-09-20 14:54:28 +00003520 mkQNaN64(),
sewardj207557a2004-08-27 12:00:18 +00003521 /* non-0 means full */
3522 get_ST_UNCHECKED(i));
3523}
3524
3525
sewardjd1725d12004-08-12 20:46:53 +00003526/* Adjust FTOP downwards by one register. */
3527
sewardj207557a2004-08-27 12:00:18 +00003528static void fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003529{
sewardj2d3f77c2004-09-22 23:49:09 +00003530 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
sewardjd1725d12004-08-12 20:46:53 +00003531}
3532
sewardj207557a2004-08-27 12:00:18 +00003533/* Adjust FTOP upwards by one register, and mark the vacated register
3534 as empty. */
sewardja58ea662004-08-15 03:12:41 +00003535
sewardj207557a2004-08-27 12:00:18 +00003536static void fp_pop ( void )
sewardja58ea662004-08-15 03:12:41 +00003537{
sewardjdb199622004-09-06 23:19:03 +00003538 put_ST_TAG(0, mkU8(0));
sewardj2d3f77c2004-09-22 23:49:09 +00003539 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
sewardja58ea662004-08-15 03:12:41 +00003540}
3541
sewardj3f61ddb2004-10-16 20:51:05 +00003542/* Clear the C2 bit of the FPU status register, for
3543 sin/cos/tan/sincos. */
3544
3545static void clear_C2 ( void )
3546{
sewardj67e002d2004-12-02 18:16:33 +00003547 put_C3210( binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2)) );
sewardj3f61ddb2004-10-16 20:51:05 +00003548}
3549
sewardjd24931d2005-03-20 12:51:39 +00003550/* Invent a plausible-looking FPU status word value:
3551 ((ftop & 7) << 11) | (c3210 & 0x4700)
3552 */
3553static IRExpr* get_FPU_sw ( void )
3554{
3555 return
3556 unop(Iop_32to16,
3557 binop(Iop_Or32,
3558 binop(Iop_Shl32,
3559 binop(Iop_And32, get_ftop(), mkU32(7)),
3560 mkU8(11)),
3561 binop(Iop_And32, get_C3210(), mkU32(0x4700))
3562 ));
3563}
3564
sewardj3f61ddb2004-10-16 20:51:05 +00003565
sewardj207557a2004-08-27 12:00:18 +00003566/* ------------------------------------------------------- */
3567/* Given all that stack-mangling junk, we can now go ahead
3568 and describe FP instructions.
3569*/
3570
sewardj3fd5e572004-09-09 22:43:51 +00003571/* ST(0) = ST(0) `op` mem64/32(addr)
sewardj207557a2004-08-27 12:00:18 +00003572 Need to check ST(0)'s tag on read, but not on write.
3573*/
sewardja58ea662004-08-15 03:12:41 +00003574static
sewardj2d49b432005-02-01 00:37:06 +00003575void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardja58ea662004-08-15 03:12:41 +00003576 IROp op, Bool dbl )
3577{
sewardj33dd31b2005-01-08 18:17:32 +00003578 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardja58ea662004-08-15 03:12:41 +00003579 if (dbl) {
sewardj3fd5e572004-09-09 22:43:51 +00003580 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003581 triop( op,
3582 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003583 get_ST(0),
3584 loadLE(Ity_F64,mkexpr(addr))
3585 ));
sewardja58ea662004-08-15 03:12:41 +00003586 } else {
sewardj3fd5e572004-09-09 22:43:51 +00003587 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003588 triop( op,
3589 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003590 get_ST(0),
3591 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3592 ));
3593 }
3594}
3595
3596
3597/* ST(0) = mem64/32(addr) `op` ST(0)
3598 Need to check ST(0)'s tag on read, but not on write.
3599*/
3600static
sewardj2d49b432005-02-01 00:37:06 +00003601void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardj883b00b2004-09-11 09:30:24 +00003602 IROp op, Bool dbl )
sewardj3fd5e572004-09-09 22:43:51 +00003603{
sewardj33dd31b2005-01-08 18:17:32 +00003604 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardj3fd5e572004-09-09 22:43:51 +00003605 if (dbl) {
3606 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003607 triop( op,
3608 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003609 loadLE(Ity_F64,mkexpr(addr)),
3610 get_ST(0)
3611 ));
3612 } else {
3613 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003614 triop( op,
3615 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003616 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3617 get_ST(0)
3618 ));
sewardja58ea662004-08-15 03:12:41 +00003619 }
3620}
3621
sewardjd1725d12004-08-12 20:46:53 +00003622
sewardjdb199622004-09-06 23:19:03 +00003623/* ST(dst) = ST(dst) `op` ST(src).
3624 Check dst and src tags when reading but not on write.
3625*/
3626static
sewardj2d49b432005-02-01 00:37:06 +00003627void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardjbdc7d212004-09-09 02:46:40 +00003628 Bool pop_after )
sewardjdb199622004-09-06 23:19:03 +00003629{
sewardj2d49b432005-02-01 00:37:06 +00003630 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3631 (Int)st_src, (Int)st_dst );
sewardjdb199622004-09-06 23:19:03 +00003632 put_ST_UNCHECKED(
3633 st_dst,
sewardjf1b5b1a2006-02-03 22:54:17 +00003634 triop( op,
3635 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3636 get_ST(st_dst),
3637 get_ST(st_src) )
sewardjdb199622004-09-06 23:19:03 +00003638 );
sewardjbdc7d212004-09-09 02:46:40 +00003639 if (pop_after)
3640 fp_pop();
3641}
3642
3643/* ST(dst) = ST(src) `op` ST(dst).
3644 Check dst and src tags when reading but not on write.
3645*/
3646static
sewardj2d49b432005-02-01 00:37:06 +00003647void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardj883b00b2004-09-11 09:30:24 +00003648 Bool pop_after )
sewardjbdc7d212004-09-09 02:46:40 +00003649{
sewardj2d49b432005-02-01 00:37:06 +00003650 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3651 (Int)st_src, (Int)st_dst );
sewardjbdc7d212004-09-09 02:46:40 +00003652 put_ST_UNCHECKED(
3653 st_dst,
sewardjf1b5b1a2006-02-03 22:54:17 +00003654 triop( op,
3655 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3656 get_ST(st_src),
3657 get_ST(st_dst) )
sewardjbdc7d212004-09-09 02:46:40 +00003658 );
3659 if (pop_after)
3660 fp_pop();
sewardjdb199622004-09-06 23:19:03 +00003661}
3662
sewardj8308aad2004-09-12 11:09:54 +00003663/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3664static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3665{
sewardj2d49b432005-02-01 00:37:06 +00003666 DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", (Int)i );
sewardj8308aad2004-09-12 11:09:54 +00003667 /* This is a bit of a hack (and isn't really right). It sets
3668 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3669 documentation implies A and S are unchanged.
3670 */
sewardjfeeb8a82004-11-30 12:30:11 +00003671 /* It's also fishy in that it is used both for COMIP and
3672 UCOMIP, and they aren't the same (although similar). */
sewardj2a9ad022004-11-25 02:46:58 +00003673 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00003674 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
3675 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj8308aad2004-09-12 11:09:54 +00003676 binop( Iop_And32,
3677 binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3678 mkU32(0x45)
3679 )));
sewardja3b7e3a2005-04-05 01:54:19 +00003680 /* Set NDEP even though it isn't used. This makes redundant-PUT
3681 elimination of previous stores to this field work better. */
3682 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj8308aad2004-09-12 11:09:54 +00003683 if (pop_after)
3684 fp_pop();
3685}
3686
sewardjdb199622004-09-06 23:19:03 +00003687
sewardjd1725d12004-08-12 20:46:53 +00003688static
sewardj52d04912005-07-03 00:52:48 +00003689UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
sewardjd1725d12004-08-12 20:46:53 +00003690{
sewardja58ea662004-08-15 03:12:41 +00003691 Int len;
3692 UInt r_src, r_dst;
sewardjc9a43662004-11-30 18:51:59 +00003693 HChar dis_buf[50];
sewardj89cd0932004-09-08 18:23:25 +00003694 IRTemp t1, t2;
sewardjd1725d12004-08-12 20:46:53 +00003695
3696 /* On entry, delta points at the second byte of the insn (the modrm
3697 byte).*/
3698 UChar first_opcode = getIByte(delta-1);
3699 UChar modrm = getIByte(delta+0);
3700
3701 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3702
3703 if (first_opcode == 0xD8) {
sewardjdb199622004-09-06 23:19:03 +00003704 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003705
3706 /* bits 5,4,3 are an opcode extension, and the modRM also
3707 specifies an address. */
3708 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3709 delta += len;
3710
3711 switch (gregOfRM(modrm)) {
3712
sewardj3fd5e572004-09-09 22:43:51 +00003713 case 0: /* FADD single-real */
3714 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3715 break;
3716
sewardj89cd0932004-09-08 18:23:25 +00003717 case 1: /* FMUL single-real */
3718 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3719 break;
3720
sewardj7ca37d92004-10-25 02:58:30 +00003721 case 2: /* FCOM single-real */
3722 DIP("fcoms %s\n", dis_buf);
3723 /* This forces C1 to zero, which isn't right. */
3724 put_C3210(
3725 binop( Iop_And32,
3726 binop(Iop_Shl32,
3727 binop(Iop_CmpF64,
3728 get_ST(0),
3729 unop(Iop_F32toF64,
3730 loadLE(Ity_F32,mkexpr(addr)))),
3731 mkU8(8)),
3732 mkU32(0x4500)
3733 ));
3734 break;
3735
3736 case 3: /* FCOMP single-real */
sewardje166ed02004-10-25 02:27:01 +00003737 DIP("fcomps %s\n", dis_buf);
3738 /* This forces C1 to zero, which isn't right. */
3739 put_C3210(
3740 binop( Iop_And32,
3741 binop(Iop_Shl32,
3742 binop(Iop_CmpF64,
3743 get_ST(0),
3744 unop(Iop_F32toF64,
3745 loadLE(Ity_F32,mkexpr(addr)))),
3746 mkU8(8)),
3747 mkU32(0x4500)
3748 ));
3749 fp_pop();
3750 break;
3751
sewardj588ea762004-09-10 18:56:32 +00003752 case 4: /* FSUB single-real */
3753 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3754 break;
3755
3756 case 5: /* FSUBR single-real */
3757 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3758 break;
3759
sewardjbdc7d212004-09-09 02:46:40 +00003760 case 6: /* FDIV single-real */
3761 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3762 break;
3763
sewardj8308aad2004-09-12 11:09:54 +00003764 case 7: /* FDIVR single-real */
3765 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3766 break;
3767
sewardj89cd0932004-09-08 18:23:25 +00003768 default:
3769 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3770 vex_printf("first_opcode == 0xD8\n");
3771 goto decode_fail;
3772 }
sewardjdb199622004-09-06 23:19:03 +00003773 } else {
3774 delta++;
3775 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003776
sewardjdb199622004-09-06 23:19:03 +00003777 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003778 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
sewardjdb199622004-09-06 23:19:03 +00003779 break;
sewardj89cd0932004-09-08 18:23:25 +00003780
sewardj3fd5e572004-09-09 22:43:51 +00003781 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3782 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3783 break;
3784
sewardje166ed02004-10-25 02:27:01 +00003785 /* Dunno if this is right */
3786 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3787 r_dst = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00003788 DIP("fcom %%st(0),%%st(%d)\n", (Int)r_dst);
sewardje166ed02004-10-25 02:27:01 +00003789 /* This forces C1 to zero, which isn't right. */
3790 put_C3210(
3791 binop( Iop_And32,
3792 binop(Iop_Shl32,
3793 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3794 mkU8(8)),
3795 mkU32(0x4500)
3796 ));
3797 break;
sewardj2d49b432005-02-01 00:37:06 +00003798
sewardj98169c52004-10-24 13:11:39 +00003799 /* Dunno if this is right */
3800 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3801 r_dst = (UInt)modrm - 0xD8;
sewardj2d49b432005-02-01 00:37:06 +00003802 DIP("fcomp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj98169c52004-10-24 13:11:39 +00003803 /* This forces C1 to zero, which isn't right. */
3804 put_C3210(
3805 binop( Iop_And32,
3806 binop(Iop_Shl32,
3807 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3808 mkU8(8)),
3809 mkU32(0x4500)
3810 ));
3811 fp_pop();
3812 break;
sewardj2d49b432005-02-01 00:37:06 +00003813
sewardj89cd0932004-09-08 18:23:25 +00003814 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003815 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
sewardj89cd0932004-09-08 18:23:25 +00003816 break;
3817
sewardj8308aad2004-09-12 11:09:54 +00003818 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3819 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3820 break;
3821
sewardj3fd5e572004-09-09 22:43:51 +00003822 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3823 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3824 break;
3825
3826 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3827 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3828 break;
3829
sewardjdb199622004-09-06 23:19:03 +00003830 default:
3831 goto decode_fail;
3832 }
3833 }
sewardjd1725d12004-08-12 20:46:53 +00003834 }
3835
3836 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3837 else
3838 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003839 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003840
3841 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00003842 specifies an address. */
sewardj89cd0932004-09-08 18:23:25 +00003843 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3844 delta += len;
3845
3846 switch (gregOfRM(modrm)) {
3847
3848 case 0: /* FLD single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003849 DIP("flds %s\n", dis_buf);
sewardj89cd0932004-09-08 18:23:25 +00003850 fp_push();
3851 put_ST(0, unop(Iop_F32toF64,
sewardj8f3debf2004-09-08 23:42:23 +00003852 loadLE(Ity_F32, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00003853 break;
3854
sewardj588ea762004-09-10 18:56:32 +00003855 case 2: /* FST single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003856 DIP("fsts %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003857 storeLE(mkexpr(addr),
3858 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj588ea762004-09-10 18:56:32 +00003859 break;
3860
sewardj89cd0932004-09-08 18:23:25 +00003861 case 3: /* FSTP single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003862 DIP("fstps %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003863 storeLE(mkexpr(addr),
3864 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj5bd4d162004-11-10 13:02:48 +00003865 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00003866 break;
3867
sewardjd24931d2005-03-20 12:51:39 +00003868 case 4: { /* FLDENV m28 */
sewardj7df596b2004-12-06 14:29:12 +00003869 /* Uses dirty helper:
sewardj4017a3b2005-06-13 12:17:27 +00003870 VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00003871 IRTemp ew = newTemp(Ity_I32);
3872 IRDirty* d = unsafeIRDirty_0_N (
3873 0/*regparms*/,
3874 "x86g_dirtyhelper_FLDENV",
3875 &x86g_dirtyhelper_FLDENV,
3876 mkIRExprVec_1( mkexpr(addr) )
3877 );
3878 d->needsBBP = True;
3879 d->tmp = ew;
3880 /* declare we're reading memory */
3881 d->mFx = Ifx_Read;
3882 d->mAddr = mkexpr(addr);
3883 d->mSize = 28;
3884
3885 /* declare we're writing guest state */
sewardj46813fc2005-06-13 12:33:36 +00003886 d->nFxState = 4;
sewardj7df596b2004-12-06 14:29:12 +00003887
3888 d->fxState[0].fx = Ifx_Write;
3889 d->fxState[0].offset = OFFB_FTOP;
3890 d->fxState[0].size = sizeof(UInt);
3891
3892 d->fxState[1].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003893 d->fxState[1].offset = OFFB_FPTAGS;
3894 d->fxState[1].size = 8 * sizeof(UChar);
sewardj7df596b2004-12-06 14:29:12 +00003895
3896 d->fxState[2].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003897 d->fxState[2].offset = OFFB_FPROUND;
3898 d->fxState[2].size = sizeof(UInt);
sewardj7df596b2004-12-06 14:29:12 +00003899
3900 d->fxState[3].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003901 d->fxState[3].offset = OFFB_FC3210;
sewardj7df596b2004-12-06 14:29:12 +00003902 d->fxState[3].size = sizeof(UInt);
3903
sewardj7df596b2004-12-06 14:29:12 +00003904 stmt( IRStmt_Dirty(d) );
3905
3906 /* ew contains any emulation warning we may need to
3907 issue. If needed, side-exit to the next insn,
3908 reporting the warning, so that Valgrind's dispatcher
3909 sees the warning. */
3910 put_emwarn( mkexpr(ew) );
3911 stmt(
3912 IRStmt_Exit(
3913 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3914 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00003915 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj7df596b2004-12-06 14:29:12 +00003916 )
3917 );
3918
sewardj33dd31b2005-01-08 18:17:32 +00003919 DIP("fldenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00003920 break;
3921 }
3922
sewardj893aada2004-11-29 19:57:54 +00003923 case 5: {/* FLDCW */
3924 /* The only thing we observe in the control word is the
sewardjd01a9632004-11-30 13:18:37 +00003925 rounding mode. Therefore, pass the 16-bit value
3926 (x87 native-format control word) to a clean helper,
3927 getting back a 64-bit value, the lower half of which
3928 is the FPROUND value to store, and the upper half of
3929 which is the emulation-warning token which may be
3930 generated.
sewardj893aada2004-11-29 19:57:54 +00003931 */
3932 /* ULong x86h_check_fldcw ( UInt ); */
3933 IRTemp t64 = newTemp(Ity_I64);
3934 IRTemp ew = newTemp(Ity_I32);
sewardj33dd31b2005-01-08 18:17:32 +00003935 DIP("fldcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00003936 assign( t64, mkIRExprCCall(
3937 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00003938 "x86g_check_fldcw",
3939 &x86g_check_fldcw,
sewardj893aada2004-11-29 19:57:54 +00003940 mkIRExprVec_1(
3941 unop( Iop_16Uto32,
3942 loadLE(Ity_I16, mkexpr(addr)))
3943 )
3944 )
3945 );
3946
sewardjd01a9632004-11-30 13:18:37 +00003947 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
sewardj893aada2004-11-29 19:57:54 +00003948 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
3949 put_emwarn( mkexpr(ew) );
3950 /* Finally, if an emulation warning was reported,
3951 side-exit to the next insn, reporting the warning,
3952 so that Valgrind's dispatcher sees the warning. */
3953 stmt(
3954 IRStmt_Exit(
3955 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3956 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00003957 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj893aada2004-11-29 19:57:54 +00003958 )
3959 );
sewardj89cd0932004-09-08 18:23:25 +00003960 break;
sewardj893aada2004-11-29 19:57:54 +00003961 }
sewardj89cd0932004-09-08 18:23:25 +00003962
sewardj7df596b2004-12-06 14:29:12 +00003963 case 6: { /* FNSTENV m28 */
3964 /* Uses dirty helper:
sewardj4017a3b2005-06-13 12:17:27 +00003965 void x86g_do_FSTENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00003966 IRDirty* d = unsafeIRDirty_0_N (
3967 0/*regparms*/,
3968 "x86g_dirtyhelper_FSTENV",
3969 &x86g_dirtyhelper_FSTENV,
3970 mkIRExprVec_1( mkexpr(addr) )
3971 );
3972 d->needsBBP = True;
3973 /* declare we're writing memory */
3974 d->mFx = Ifx_Write;
3975 d->mAddr = mkexpr(addr);
3976 d->mSize = 28;
3977
3978 /* declare we're reading guest state */
3979 d->nFxState = 4;
3980
3981 d->fxState[0].fx = Ifx_Read;
3982 d->fxState[0].offset = OFFB_FTOP;
3983 d->fxState[0].size = sizeof(UInt);
3984
3985 d->fxState[1].fx = Ifx_Read;
3986 d->fxState[1].offset = OFFB_FPTAGS;
3987 d->fxState[1].size = 8 * sizeof(UChar);
3988
3989 d->fxState[2].fx = Ifx_Read;
3990 d->fxState[2].offset = OFFB_FPROUND;
3991 d->fxState[2].size = sizeof(UInt);
3992
3993 d->fxState[3].fx = Ifx_Read;
3994 d->fxState[3].offset = OFFB_FC3210;
3995 d->fxState[3].size = sizeof(UInt);
3996
3997 stmt( IRStmt_Dirty(d) );
3998
sewardj33dd31b2005-01-08 18:17:32 +00003999 DIP("fnstenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00004000 break;
4001 }
4002
sewardj588ea762004-09-10 18:56:32 +00004003 case 7: /* FNSTCW */
sewardj893aada2004-11-29 19:57:54 +00004004 /* Fake up a native x87 FPU control word. The only
sewardjd01a9632004-11-30 13:18:37 +00004005 thing it depends on is FPROUND[1:0], so call a clean
sewardj893aada2004-11-29 19:57:54 +00004006 helper to cook it up. */
sewardjd01a9632004-11-30 13:18:37 +00004007 /* UInt x86h_create_fpucw ( UInt fpround ) */
sewardj33dd31b2005-01-08 18:17:32 +00004008 DIP("fnstcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00004009 storeLE(
4010 mkexpr(addr),
4011 unop( Iop_32to16,
4012 mkIRExprCCall(
4013 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00004014 "x86g_create_fpucw", &x86g_create_fpucw,
sewardjd01a9632004-11-30 13:18:37 +00004015 mkIRExprVec_1( get_fpround() )
sewardj893aada2004-11-29 19:57:54 +00004016 )
4017 )
4018 );
sewardj89cd0932004-09-08 18:23:25 +00004019 break;
4020
4021 default:
4022 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4023 vex_printf("first_opcode == 0xD9\n");
4024 goto decode_fail;
4025 }
4026
sewardjbb53f8c2004-08-14 11:50:01 +00004027 } else {
4028 delta++;
4029 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00004030
sewardjbb53f8c2004-08-14 11:50:01 +00004031 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00004032 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00004033 DIP("fld %%st(%d)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004034 t1 = newTemp(Ity_F64);
4035 assign(t1, get_ST(r_src));
4036 fp_push();
4037 put_ST(0, mkexpr(t1));
sewardjbb53f8c2004-08-14 11:50:01 +00004038 break;
4039
sewardj89cd0932004-09-08 18:23:25 +00004040 case 0xC8 ... 0xCF: /* FXCH %st(?) */
4041 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00004042 DIP("fxch %%st(%d)\n", (Int)r_src);
sewardj89cd0932004-09-08 18:23:25 +00004043 t1 = newTemp(Ity_F64);
4044 t2 = newTemp(Ity_F64);
4045 assign(t1, get_ST(0));
4046 assign(t2, get_ST(r_src));
4047 put_ST_UNCHECKED(0, mkexpr(t2));
4048 put_ST_UNCHECKED(r_src, mkexpr(t1));
4049 break;
4050
sewardjcfded9a2004-09-09 11:44:16 +00004051 case 0xE0: /* FCHS */
4052 DIP("fchs\n");
4053 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4054 break;
4055
sewardj883b00b2004-09-11 09:30:24 +00004056 case 0xE1: /* FABS */
4057 DIP("fabs\n");
4058 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4059 break;
sewardjc4be80c2004-09-10 16:17:45 +00004060
sewardj1c318772005-03-19 14:27:04 +00004061 case 0xE4: /* FTST */
4062 DIP("ftst\n");
4063 /* This forces C1 to zero, which isn't right. */
4064 /* Well, in fact the Intel docs say (bizarrely): "C1 is
4065 set to 0 if stack underflow occurred; otherwise, set
4066 to 0" which is pretty nonsensical. I guess it's a
4067 typo. */
4068 put_C3210(
4069 binop( Iop_And32,
4070 binop(Iop_Shl32,
4071 binop(Iop_CmpF64,
4072 get_ST(0),
4073 IRExpr_Const(IRConst_F64i(0x0ULL))),
4074 mkU8(8)),
4075 mkU32(0x4500)
4076 ));
4077 break;
4078
sewardj883b00b2004-09-11 09:30:24 +00004079 case 0xE5: { /* FXAM */
4080 /* This is an interesting one. It examines %st(0),
4081 regardless of whether the tag says it's empty or not.
4082 Here, just pass both the tag (in our format) and the
4083 value (as a double, actually a ULong) to a helper
4084 function. */
sewardjf9655262004-10-31 20:02:16 +00004085 IRExpr** args
4086 = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
4087 unop(Iop_ReinterpF64asI64,
4088 get_ST_UNCHECKED(0)) );
4089 put_C3210(mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00004090 Ity_I32,
sewardjf9655262004-10-31 20:02:16 +00004091 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00004092 "x86g_calculate_FXAM", &x86g_calculate_FXAM,
sewardj8ea867b2004-10-30 19:03:02 +00004093 args
4094 ));
sewardj33dd31b2005-01-08 18:17:32 +00004095 DIP("fxam\n");
sewardj883b00b2004-09-11 09:30:24 +00004096 break;
4097 }
4098
4099 case 0xE8: /* FLD1 */
sewardj33dd31b2005-01-08 18:17:32 +00004100 DIP("fld1\n");
sewardjce646f22004-08-31 23:55:54 +00004101 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004102 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
4103 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
sewardjce646f22004-08-31 23:55:54 +00004104 break;
4105
sewardj37158712004-10-15 21:23:12 +00004106 case 0xE9: /* FLDL2T */
sewardj33dd31b2005-01-08 18:17:32 +00004107 DIP("fldl2t\n");
sewardj37158712004-10-15 21:23:12 +00004108 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004109 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
4110 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
sewardj37158712004-10-15 21:23:12 +00004111 break;
4112
sewardj8308aad2004-09-12 11:09:54 +00004113 case 0xEA: /* FLDL2E */
sewardj33dd31b2005-01-08 18:17:32 +00004114 DIP("fldl2e\n");
sewardj8308aad2004-09-12 11:09:54 +00004115 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004116 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
4117 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
sewardj8308aad2004-09-12 11:09:54 +00004118 break;
4119
sewardja0d48d62004-09-20 21:19:03 +00004120 case 0xEB: /* FLDPI */
sewardj33dd31b2005-01-08 18:17:32 +00004121 DIP("fldpi\n");
sewardja0d48d62004-09-20 21:19:03 +00004122 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004123 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
4124 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
sewardja0d48d62004-09-20 21:19:03 +00004125 break;
4126
sewardjdb199622004-09-06 23:19:03 +00004127 case 0xEC: /* FLDLG2 */
sewardj33dd31b2005-01-08 18:17:32 +00004128 DIP("fldlg2\n");
sewardjdb199622004-09-06 23:19:03 +00004129 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004130 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
4131 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
sewardjdb199622004-09-06 23:19:03 +00004132 break;
4133
4134 case 0xED: /* FLDLN2 */
sewardj33dd31b2005-01-08 18:17:32 +00004135 DIP("fldln2\n");
sewardjdb199622004-09-06 23:19:03 +00004136 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004137 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
4138 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
sewardjdb199622004-09-06 23:19:03 +00004139 break;
4140
sewardja58ea662004-08-15 03:12:41 +00004141 case 0xEE: /* FLDZ */
sewardj33dd31b2005-01-08 18:17:32 +00004142 DIP("fldz\n");
sewardj207557a2004-08-27 12:00:18 +00004143 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004144 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
4145 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
sewardja58ea662004-08-15 03:12:41 +00004146 break;
4147
sewardj06c32a02004-09-12 12:07:34 +00004148 case 0xF0: /* F2XM1 */
4149 DIP("f2xm1\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004150 put_ST_UNCHECKED(0,
4151 binop(Iop_2xm1F64,
4152 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4153 get_ST(0)));
sewardj06c32a02004-09-12 12:07:34 +00004154 break;
4155
sewardj52ace3e2004-09-11 17:10:08 +00004156 case 0xF1: /* FYL2X */
4157 DIP("fyl2x\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004158 put_ST_UNCHECKED(1,
4159 triop(Iop_Yl2xF64,
4160 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4161 get_ST(1),
4162 get_ST(0)));
sewardj52ace3e2004-09-11 17:10:08 +00004163 fp_pop();
4164 break;
4165
sewardj99016a72004-10-15 22:09:17 +00004166 case 0xF2: /* FPTAN */
4167 DIP("ftan\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004168 put_ST_UNCHECKED(0,
4169 binop(Iop_TanF64,
4170 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4171 get_ST(0)));
sewardj99016a72004-10-15 22:09:17 +00004172 fp_push();
4173 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004174 clear_C2(); /* HACK */
sewardj99016a72004-10-15 22:09:17 +00004175 break;
4176
sewardjcfded9a2004-09-09 11:44:16 +00004177 case 0xF3: /* FPATAN */
4178 DIP("fpatan\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004179 put_ST_UNCHECKED(1,
4180 triop(Iop_AtanF64,
4181 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4182 get_ST(1),
4183 get_ST(0)));
sewardjcfded9a2004-09-09 11:44:16 +00004184 fp_pop();
4185 break;
4186
sewardjf1b5b1a2006-02-03 22:54:17 +00004187 case 0xF4: { /* FXTRACT */
sewardjfda10af2005-10-03 01:02:40 +00004188 IRTemp argF = newTemp(Ity_F64);
4189 IRTemp sigF = newTemp(Ity_F64);
4190 IRTemp expF = newTemp(Ity_F64);
4191 IRTemp argI = newTemp(Ity_I64);
4192 IRTemp sigI = newTemp(Ity_I64);
4193 IRTemp expI = newTemp(Ity_I64);
4194 DIP("fxtract\n");
4195 assign( argF, get_ST(0) );
4196 assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
4197 assign( sigI,
sewardj879cee02006-03-07 01:15:50 +00004198 mkIRExprCCall(
4199 Ity_I64, 0/*regparms*/,
4200 "x86amd64g_calculate_FXTRACT",
4201 &x86amd64g_calculate_FXTRACT,
4202 mkIRExprVec_2( mkexpr(argI),
4203 mkIRExpr_HWord(0)/*sig*/ ))
4204 );
sewardjfda10af2005-10-03 01:02:40 +00004205 assign( expI,
sewardj879cee02006-03-07 01:15:50 +00004206 mkIRExprCCall(
4207 Ity_I64, 0/*regparms*/,
4208 "x86amd64g_calculate_FXTRACT",
4209 &x86amd64g_calculate_FXTRACT,
4210 mkIRExprVec_2( mkexpr(argI),
4211 mkIRExpr_HWord(1)/*exp*/ ))
4212 );
sewardjfda10af2005-10-03 01:02:40 +00004213 assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
4214 assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
4215 /* exponent */
4216 put_ST_UNCHECKED(0, mkexpr(expF) );
4217 fp_push();
4218 /* significand */
4219 put_ST(0, mkexpr(sigF) );
4220 break;
4221 }
4222
sewardj442d0be2004-10-15 22:57:13 +00004223 case 0xF5: { /* FPREM1 -- IEEE compliant */
4224 IRTemp a1 = newTemp(Ity_F64);
4225 IRTemp a2 = newTemp(Ity_F64);
4226 DIP("fprem1\n");
4227 /* Do FPREM1 twice, once to get the remainder, and once
4228 to get the C3210 flag values. */
4229 assign( a1, get_ST(0) );
4230 assign( a2, get_ST(1) );
sewardjf47286e2006-02-04 15:20:13 +00004231 put_ST_UNCHECKED(0,
4232 triop(Iop_PRem1F64,
4233 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4234 mkexpr(a1),
4235 mkexpr(a2)));
4236 put_C3210(
4237 triop(Iop_PRem1C3210F64,
4238 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4239 mkexpr(a1),
4240 mkexpr(a2)) );
sewardj442d0be2004-10-15 22:57:13 +00004241 break;
4242 }
4243
sewardjfeeb8a82004-11-30 12:30:11 +00004244 case 0xF7: /* FINCSTP */
4245 DIP("fprem\n");
4246 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4247 break;
4248
sewardj46de4072004-09-11 19:23:24 +00004249 case 0xF8: { /* FPREM -- not IEEE compliant */
4250 IRTemp a1 = newTemp(Ity_F64);
4251 IRTemp a2 = newTemp(Ity_F64);
4252 DIP("fprem\n");
4253 /* Do FPREM twice, once to get the remainder, and once
4254 to get the C3210 flag values. */
4255 assign( a1, get_ST(0) );
4256 assign( a2, get_ST(1) );
sewardjf47286e2006-02-04 15:20:13 +00004257 put_ST_UNCHECKED(0,
4258 triop(Iop_PRemF64,
4259 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4260 mkexpr(a1),
4261 mkexpr(a2)));
4262 put_C3210(
4263 triop(Iop_PRemC3210F64,
4264 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4265 mkexpr(a1),
4266 mkexpr(a2)) );
sewardj46de4072004-09-11 19:23:24 +00004267 break;
4268 }
4269
sewardj8308aad2004-09-12 11:09:54 +00004270 case 0xF9: /* FYL2XP1 */
4271 DIP("fyl2xp1\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004272 put_ST_UNCHECKED(1,
4273 triop(Iop_Yl2xp1F64,
4274 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4275 get_ST(1),
4276 get_ST(0)));
sewardj8308aad2004-09-12 11:09:54 +00004277 fp_pop();
4278 break;
4279
sewardjc4be80c2004-09-10 16:17:45 +00004280 case 0xFA: /* FSQRT */
4281 DIP("fsqrt\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004282 put_ST_UNCHECKED(0,
4283 binop(Iop_SqrtF64,
4284 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4285 get_ST(0)));
sewardjc4be80c2004-09-10 16:17:45 +00004286 break;
4287
sewardj519d66f2004-12-15 11:57:58 +00004288 case 0xFB: { /* FSINCOS */
4289 IRTemp a1 = newTemp(Ity_F64);
4290 assign( a1, get_ST(0) );
4291 DIP("fsincos\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004292 put_ST_UNCHECKED(0,
4293 binop(Iop_SinF64,
4294 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4295 mkexpr(a1)));
sewardj519d66f2004-12-15 11:57:58 +00004296 fp_push();
sewardjf1b5b1a2006-02-03 22:54:17 +00004297 put_ST(0,
4298 binop(Iop_CosF64,
4299 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4300 mkexpr(a1)));
sewardj88a69242005-04-01 20:19:20 +00004301 clear_C2(); /* HACK */
sewardj519d66f2004-12-15 11:57:58 +00004302 break;
4303 }
4304
sewardje6709112004-09-10 18:37:18 +00004305 case 0xFC: /* FRNDINT */
4306 DIP("frndint\n");
4307 put_ST_UNCHECKED(0,
sewardjb183b852006-02-03 16:08:03 +00004308 binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
sewardje6709112004-09-10 18:37:18 +00004309 break;
4310
sewardj06c32a02004-09-12 12:07:34 +00004311 case 0xFD: /* FSCALE */
4312 DIP("fscale\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004313 put_ST_UNCHECKED(0,
4314 triop(Iop_ScaleF64,
4315 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4316 get_ST(0),
4317 get_ST(1)));
sewardj06c32a02004-09-12 12:07:34 +00004318 break;
4319
sewardjcfded9a2004-09-09 11:44:16 +00004320 case 0xFE: /* FSIN */
4321 DIP("fsin\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004322 put_ST_UNCHECKED(0,
4323 binop(Iop_SinF64,
4324 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4325 get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004326 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00004327 break;
4328
4329 case 0xFF: /* FCOS */
4330 DIP("fcos\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004331 put_ST_UNCHECKED(0,
4332 binop(Iop_CosF64,
4333 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4334 get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004335 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00004336 break;
4337
sewardjbb53f8c2004-08-14 11:50:01 +00004338 default:
4339 goto decode_fail;
4340 }
4341 }
sewardjd1725d12004-08-12 20:46:53 +00004342 }
4343
4344 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4345 else
4346 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00004347
4348 if (modrm < 0xC0) {
4349
sewardjfeeb8a82004-11-30 12:30:11 +00004350 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjbb53f8c2004-08-14 11:50:01 +00004351 specifies an address. */
sewardjce646f22004-08-31 23:55:54 +00004352 IROp fop;
sewardjbb53f8c2004-08-14 11:50:01 +00004353 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4354 delta += len;
sewardjbb53f8c2004-08-14 11:50:01 +00004355 switch (gregOfRM(modrm)) {
sewardjce646f22004-08-31 23:55:54 +00004356
sewardjdb199622004-09-06 23:19:03 +00004357 case 0: /* FIADD m32int */ /* ST(0) += m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004358 DIP("fiaddl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004359 fop = Iop_AddF64;
4360 goto do_fop_m32;
sewardjdb199622004-09-06 23:19:03 +00004361
sewardj207557a2004-08-27 12:00:18 +00004362 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004363 DIP("fimull %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004364 fop = Iop_MulF64;
4365 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004366
sewardj071895f2005-07-29 11:28:38 +00004367 case 2: /* FICOM m32int */
4368 DIP("ficoml %s\n", dis_buf);
4369 /* This forces C1 to zero, which isn't right. */
4370 put_C3210(
4371 binop( Iop_And32,
4372 binop(Iop_Shl32,
4373 binop(Iop_CmpF64,
4374 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00004375 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00004376 loadLE(Ity_I32,mkexpr(addr)))),
4377 mkU8(8)),
4378 mkU32(0x4500)
4379 ));
4380 break;
4381
4382 case 3: /* FICOMP m32int */
4383 DIP("ficompl %s\n", dis_buf);
4384 /* This forces C1 to zero, which isn't right. */
4385 put_C3210(
4386 binop( Iop_And32,
4387 binop(Iop_Shl32,
4388 binop(Iop_CmpF64,
4389 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00004390 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00004391 loadLE(Ity_I32,mkexpr(addr)))),
4392 mkU8(8)),
4393 mkU32(0x4500)
4394 ));
4395 fp_pop();
4396 break;
4397
sewardjce646f22004-08-31 23:55:54 +00004398 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004399 DIP("fisubl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004400 fop = Iop_SubF64;
4401 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004402
sewardj8308aad2004-09-12 11:09:54 +00004403 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004404 DIP("fisubrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004405 fop = Iop_SubF64;
4406 goto do_foprev_m32;
sewardj8308aad2004-09-12 11:09:54 +00004407
sewardjce646f22004-08-31 23:55:54 +00004408 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
sewardj36917e92005-03-21 00:12:15 +00004409 DIP("fidivl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004410 fop = Iop_DivF64;
4411 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004412
sewardjc4eaff32004-09-10 20:25:11 +00004413 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004414 DIP("fidivrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004415 fop = Iop_DivF64;
4416 goto do_foprev_m32;
sewardjc4eaff32004-09-10 20:25:11 +00004417
sewardjce646f22004-08-31 23:55:54 +00004418 do_fop_m32:
sewardj207557a2004-08-27 12:00:18 +00004419 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004420 triop(fop,
4421 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj207557a2004-08-27 12:00:18 +00004422 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00004423 unop(Iop_I32StoF64,
sewardj89cd0932004-09-08 18:23:25 +00004424 loadLE(Ity_I32, mkexpr(addr)))));
sewardjbb53f8c2004-08-14 11:50:01 +00004425 break;
4426
sewardjc4eaff32004-09-10 20:25:11 +00004427 do_foprev_m32:
4428 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004429 triop(fop,
4430 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6c299f32009-12-31 18:00:12 +00004431 unop(Iop_I32StoF64,
sewardjc4eaff32004-09-10 20:25:11 +00004432 loadLE(Ity_I32, mkexpr(addr))),
4433 get_ST(0)));
4434 break;
4435
sewardjbb53f8c2004-08-14 11:50:01 +00004436 default:
4437 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4438 vex_printf("first_opcode == 0xDA\n");
4439 goto decode_fail;
4440 }
sewardj4cb918d2004-12-03 19:43:31 +00004441
sewardjbb53f8c2004-08-14 11:50:01 +00004442 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004443
4444 delta++;
4445 switch (modrm) {
4446
sewardj519d66f2004-12-15 11:57:58 +00004447 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4448 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00004449 DIP("fcmovb %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004450 put_ST_UNCHECKED(0,
4451 IRExpr_Mux0X(
4452 unop(Iop_1Uto8,
4453 mk_x86g_calculate_condition(X86CondB)),
4454 get_ST(0), get_ST(r_src)) );
4455 break;
4456
sewardj3fd5e572004-09-09 22:43:51 +00004457 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4458 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00004459 DIP("fcmovz %%st(%d), %%st(0)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004460 put_ST_UNCHECKED(0,
sewardj3fd5e572004-09-09 22:43:51 +00004461 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004462 unop(Iop_1Uto8,
4463 mk_x86g_calculate_condition(X86CondZ)),
sewardj3fd5e572004-09-09 22:43:51 +00004464 get_ST(0), get_ST(r_src)) );
4465 break;
4466
sewardj519d66f2004-12-15 11:57:58 +00004467 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4468 r_src = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004469 DIP("fcmovbe %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004470 put_ST_UNCHECKED(0,
4471 IRExpr_Mux0X(
4472 unop(Iop_1Uto8,
4473 mk_x86g_calculate_condition(X86CondBE)),
4474 get_ST(0), get_ST(r_src)) );
4475 break;
4476
sewardj8253ad32005-07-04 10:26:32 +00004477 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
4478 r_src = (UInt)modrm - 0xD8;
sewardjd8862cf2006-03-06 19:17:17 +00004479 DIP("fcmovu %%st(%d), %%st(0)\n", (Int)r_src);
sewardj8253ad32005-07-04 10:26:32 +00004480 put_ST_UNCHECKED(0,
4481 IRExpr_Mux0X(
4482 unop(Iop_1Uto8,
4483 mk_x86g_calculate_condition(X86CondP)),
4484 get_ST(0), get_ST(r_src)) );
4485 break;
4486
sewardjbdc7d212004-09-09 02:46:40 +00004487 case 0xE9: /* FUCOMPP %st(0),%st(1) */
4488 DIP("fucompp %%st(0),%%st(1)\n");
sewardjc4be80c2004-09-10 16:17:45 +00004489 /* This forces C1 to zero, which isn't right. */
4490 put_C3210(
4491 binop( Iop_And32,
4492 binop(Iop_Shl32,
4493 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4494 mkU8(8)),
4495 mkU32(0x4500)
4496 ));
sewardjbdc7d212004-09-09 02:46:40 +00004497 fp_pop();
4498 fp_pop();
4499 break;
4500
sewardj5bd4d162004-11-10 13:02:48 +00004501 default:
sewardjbdc7d212004-09-09 02:46:40 +00004502 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004503 }
sewardjbdc7d212004-09-09 02:46:40 +00004504
sewardjbb53f8c2004-08-14 11:50:01 +00004505 }
sewardjd1725d12004-08-12 20:46:53 +00004506 }
4507
4508 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4509 else
4510 if (first_opcode == 0xDB) {
sewardj89cd0932004-09-08 18:23:25 +00004511 if (modrm < 0xC0) {
4512
sewardjfeeb8a82004-11-30 12:30:11 +00004513 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004514 specifies an address. */
4515 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4516 delta += len;
4517
4518 switch (gregOfRM(modrm)) {
4519
4520 case 0: /* FILD m32int */
4521 DIP("fildl %s\n", dis_buf);
4522 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00004523 put_ST(0, unop(Iop_I32StoF64,
sewardj89cd0932004-09-08 18:23:25 +00004524 loadLE(Ity_I32, mkexpr(addr))));
4525 break;
4526
sewardjdd5d2042006-08-03 15:03:19 +00004527 case 1: /* FISTTPL m32 (SSE3) */
4528 DIP("fisttpl %s\n", dis_buf);
4529 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004530 binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjdd5d2042006-08-03 15:03:19 +00004531 fp_pop();
4532 break;
4533
sewardj8f3debf2004-09-08 23:42:23 +00004534 case 2: /* FIST m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004535 DIP("fistl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004536 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004537 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
sewardj8f3debf2004-09-08 23:42:23 +00004538 break;
4539
sewardj89cd0932004-09-08 18:23:25 +00004540 case 3: /* FISTP m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004541 DIP("fistpl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004542 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004543 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
sewardj5bd4d162004-11-10 13:02:48 +00004544 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004545 break;
sewardj17442fe2004-09-20 14:54:28 +00004546
sewardjb3bce0e2004-09-14 23:20:10 +00004547 case 5: { /* FLD extended-real */
sewardj7cb49d72004-10-24 22:31:25 +00004548 /* Uses dirty helper:
sewardj56579232005-03-26 21:49:42 +00004549 ULong x86g_loadF80le ( UInt )
sewardj7cb49d72004-10-24 22:31:25 +00004550 addr holds the address. First, do a dirty call to
sewardjb3bce0e2004-09-14 23:20:10 +00004551 get hold of the data. */
sewardjc5fc7aa2004-10-27 23:00:55 +00004552 IRTemp val = newTemp(Ity_I64);
4553 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4554
sewardj8ea867b2004-10-30 19:03:02 +00004555 IRDirty* d = unsafeIRDirty_1_N (
4556 val,
sewardj2a9ad022004-11-25 02:46:58 +00004557 0/*regparms*/,
sewardj8f40b072005-08-23 19:30:58 +00004558 "x86g_dirtyhelper_loadF80le",
4559 &x86g_dirtyhelper_loadF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004560 args
4561 );
sewardjb3bce0e2004-09-14 23:20:10 +00004562 /* declare that we're reading memory */
4563 d->mFx = Ifx_Read;
sewardj17442fe2004-09-20 14:54:28 +00004564 d->mAddr = mkexpr(addr);
sewardjb3bce0e2004-09-14 23:20:10 +00004565 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004566
4567 /* execute the dirty call, dumping the result in val. */
sewardjb3bce0e2004-09-14 23:20:10 +00004568 stmt( IRStmt_Dirty(d) );
4569 fp_push();
sewardjc5fc7aa2004-10-27 23:00:55 +00004570 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4571
sewardj33dd31b2005-01-08 18:17:32 +00004572 DIP("fldt %s\n", dis_buf);
sewardjb3bce0e2004-09-14 23:20:10 +00004573 break;
4574 }
sewardj17442fe2004-09-20 14:54:28 +00004575
4576 case 7: { /* FSTP extended-real */
sewardj9fc9e782004-11-26 17:57:40 +00004577 /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
sewardjc5fc7aa2004-10-27 23:00:55 +00004578 IRExpr** args
4579 = mkIRExprVec_2( mkexpr(addr),
4580 unop(Iop_ReinterpF64asI64, get_ST(0)) );
4581
sewardj8ea867b2004-10-30 19:03:02 +00004582 IRDirty* d = unsafeIRDirty_0_N (
sewardjf9655262004-10-31 20:02:16 +00004583 0/*regparms*/,
sewardj8f40b072005-08-23 19:30:58 +00004584 "x86g_dirtyhelper_storeF80le",
4585 &x86g_dirtyhelper_storeF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004586 args
4587 );
sewardj17442fe2004-09-20 14:54:28 +00004588 /* declare we're writing memory */
4589 d->mFx = Ifx_Write;
4590 d->mAddr = mkexpr(addr);
4591 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004592
sewardj17442fe2004-09-20 14:54:28 +00004593 /* execute the dirty call. */
4594 stmt( IRStmt_Dirty(d) );
4595 fp_pop();
sewardjc5fc7aa2004-10-27 23:00:55 +00004596
sewardj33dd31b2005-01-08 18:17:32 +00004597 DIP("fstpt\n %s", dis_buf);
sewardj17442fe2004-09-20 14:54:28 +00004598 break;
4599 }
4600
sewardjb3bce0e2004-09-14 23:20:10 +00004601 default:
sewardj89cd0932004-09-08 18:23:25 +00004602 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4603 vex_printf("first_opcode == 0xDB\n");
4604 goto decode_fail;
4605 }
4606
4607 } else {
sewardj8308aad2004-09-12 11:09:54 +00004608
4609 delta++;
4610 switch (modrm) {
4611
sewardj519d66f2004-12-15 11:57:58 +00004612 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
4613 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00004614 DIP("fcmovnb %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004615 put_ST_UNCHECKED(0,
4616 IRExpr_Mux0X(
4617 unop(Iop_1Uto8,
4618 mk_x86g_calculate_condition(X86CondNB)),
4619 get_ST(0), get_ST(r_src)) );
4620 break;
4621
sewardj4e82db72004-10-16 11:32:15 +00004622 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4623 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00004624 DIP("fcmovnz %%st(%d), %%st(0)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004625 put_ST_UNCHECKED(0,
sewardj4e82db72004-10-16 11:32:15 +00004626 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004627 unop(Iop_1Uto8,
4628 mk_x86g_calculate_condition(X86CondNZ)),
sewardj4e82db72004-10-16 11:32:15 +00004629 get_ST(0), get_ST(r_src)) );
4630 break;
4631
sewardj519d66f2004-12-15 11:57:58 +00004632 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
4633 r_src = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004634 DIP("fcmovnbe %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004635 put_ST_UNCHECKED(0,
4636 IRExpr_Mux0X(
4637 unop(Iop_1Uto8,
4638 mk_x86g_calculate_condition(X86CondNBE)),
4639 get_ST(0), get_ST(r_src)) );
4640 break;
4641
sewardj8253ad32005-07-04 10:26:32 +00004642 case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
4643 r_src = (UInt)modrm - 0xD8;
4644 DIP("fcmovnu %%st(%d), %%st(0)\n", (Int)r_src);
4645 put_ST_UNCHECKED(0,
4646 IRExpr_Mux0X(
4647 unop(Iop_1Uto8,
4648 mk_x86g_calculate_condition(X86CondNP)),
4649 get_ST(0), get_ST(r_src)) );
4650 break;
4651
sewardj7df596b2004-12-06 14:29:12 +00004652 case 0xE2:
4653 DIP("fnclex\n");
4654 break;
4655
sewardja0e83b02005-01-06 12:36:38 +00004656 case 0xE3: {
4657 /* Uses dirty helper:
4658 void x86g_do_FINIT ( VexGuestX86State* ) */
4659 IRDirty* d = unsafeIRDirty_0_N (
4660 0/*regparms*/,
4661 "x86g_dirtyhelper_FINIT",
4662 &x86g_dirtyhelper_FINIT,
4663 mkIRExprVec_0()
4664 );
4665 d->needsBBP = True;
4666
4667 /* declare we're writing guest state */
4668 d->nFxState = 5;
4669
4670 d->fxState[0].fx = Ifx_Write;
4671 d->fxState[0].offset = OFFB_FTOP;
4672 d->fxState[0].size = sizeof(UInt);
4673
4674 d->fxState[1].fx = Ifx_Write;
4675 d->fxState[1].offset = OFFB_FPREGS;
4676 d->fxState[1].size = 8 * sizeof(ULong);
4677
4678 d->fxState[2].fx = Ifx_Write;
4679 d->fxState[2].offset = OFFB_FPTAGS;
4680 d->fxState[2].size = 8 * sizeof(UChar);
4681
4682 d->fxState[3].fx = Ifx_Write;
4683 d->fxState[3].offset = OFFB_FPROUND;
4684 d->fxState[3].size = sizeof(UInt);
4685
4686 d->fxState[4].fx = Ifx_Write;
4687 d->fxState[4].offset = OFFB_FC3210;
4688 d->fxState[4].size = sizeof(UInt);
4689
4690 stmt( IRStmt_Dirty(d) );
4691
sewardj33dd31b2005-01-08 18:17:32 +00004692 DIP("fninit\n");
sewardja0e83b02005-01-06 12:36:38 +00004693 break;
4694 }
4695
sewardj8308aad2004-09-12 11:09:54 +00004696 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4697 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4698 break;
4699
sewardj37158712004-10-15 21:23:12 +00004700 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4701 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4702 break;
4703
sewardj8308aad2004-09-12 11:09:54 +00004704 default:
4705 goto decode_fail;
sewardj17442fe2004-09-20 14:54:28 +00004706 }
sewardj89cd0932004-09-08 18:23:25 +00004707 }
sewardjd1725d12004-08-12 20:46:53 +00004708 }
4709
4710 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4711 else
4712 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00004713 if (modrm < 0xC0) {
4714
sewardj89cd0932004-09-08 18:23:25 +00004715 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00004716 specifies an address. */
sewardja58ea662004-08-15 03:12:41 +00004717 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4718 delta += len;
4719
4720 switch (gregOfRM(modrm)) {
4721
4722 case 0: /* FADD double-real */
4723 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4724 break;
4725
sewardjcfded9a2004-09-09 11:44:16 +00004726 case 1: /* FMUL double-real */
4727 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4728 break;
4729
sewardje166ed02004-10-25 02:27:01 +00004730 case 2: /* FCOM double-real */
4731 DIP("fcoml %s\n", dis_buf);
4732 /* This forces C1 to zero, which isn't right. */
4733 put_C3210(
4734 binop( Iop_And32,
4735 binop(Iop_Shl32,
4736 binop(Iop_CmpF64,
4737 get_ST(0),
4738 loadLE(Ity_F64,mkexpr(addr))),
4739 mkU8(8)),
4740 mkU32(0x4500)
4741 ));
4742 break;
4743
sewardj883b00b2004-09-11 09:30:24 +00004744 case 3: /* FCOMP double-real */
sewardje166ed02004-10-25 02:27:01 +00004745 DIP("fcompl %s\n", dis_buf);
sewardj883b00b2004-09-11 09:30:24 +00004746 /* This forces C1 to zero, which isn't right. */
4747 put_C3210(
4748 binop( Iop_And32,
4749 binop(Iop_Shl32,
4750 binop(Iop_CmpF64,
4751 get_ST(0),
4752 loadLE(Ity_F64,mkexpr(addr))),
4753 mkU8(8)),
4754 mkU32(0x4500)
4755 ));
4756 fp_pop();
4757 break;
4758
sewardjcfded9a2004-09-09 11:44:16 +00004759 case 4: /* FSUB double-real */
4760 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4761 break;
4762
sewardj3fd5e572004-09-09 22:43:51 +00004763 case 5: /* FSUBR double-real */
4764 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4765 break;
4766
sewardjcfded9a2004-09-09 11:44:16 +00004767 case 6: /* FDIV double-real */
4768 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4769 break;
4770
sewardj883b00b2004-09-11 09:30:24 +00004771 case 7: /* FDIVR double-real */
4772 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4773 break;
4774
sewardja58ea662004-08-15 03:12:41 +00004775 default:
4776 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4777 vex_printf("first_opcode == 0xDC\n");
4778 goto decode_fail;
4779 }
4780
4781 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004782
4783 delta++;
4784 switch (modrm) {
4785
sewardj3fd5e572004-09-09 22:43:51 +00004786 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4787 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4788 break;
4789
sewardjcfded9a2004-09-09 11:44:16 +00004790 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4791 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4792 break;
4793
sewardj47341042004-09-19 11:55:46 +00004794 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4795 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4796 break;
4797
sewardjcfded9a2004-09-09 11:44:16 +00004798 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4799 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4800 break;
4801
sewardja0d48d62004-09-20 21:19:03 +00004802 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4803 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4804 break;
4805
sewardjbdc7d212004-09-09 02:46:40 +00004806 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4807 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4808 break;
4809
4810 default:
4811 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004812 }
sewardjbdc7d212004-09-09 02:46:40 +00004813
sewardja58ea662004-08-15 03:12:41 +00004814 }
sewardjd1725d12004-08-12 20:46:53 +00004815 }
4816
4817 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
4818 else
4819 if (first_opcode == 0xDD) {
4820
4821 if (modrm < 0xC0) {
4822
sewardjfeeb8a82004-11-30 12:30:11 +00004823 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00004824 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00004825 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4826 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00004827
4828 switch (gregOfRM(modrm)) {
4829
4830 case 0: /* FLD double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004831 DIP("fldl %s\n", dis_buf);
sewardj207557a2004-08-27 12:00:18 +00004832 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00004833 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardjbb53f8c2004-08-14 11:50:01 +00004834 break;
sewardjd1725d12004-08-12 20:46:53 +00004835
sewardjdd5d2042006-08-03 15:03:19 +00004836 case 1: /* FISTTPQ m64 (SSE3) */
4837 DIP("fistppll %s\n", dis_buf);
4838 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004839 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjdd5d2042006-08-03 15:03:19 +00004840 fp_pop();
4841 break;
4842
sewardjd1725d12004-08-12 20:46:53 +00004843 case 2: /* FST double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004844 DIP("fstl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004845 storeLE(mkexpr(addr), get_ST(0));
sewardjd1725d12004-08-12 20:46:53 +00004846 break;
sewardj89cd0932004-09-08 18:23:25 +00004847
sewardja58ea662004-08-15 03:12:41 +00004848 case 3: /* FSTP double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004849 DIP("fstpl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004850 storeLE(mkexpr(addr), get_ST(0));
4851 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004852 break;
sewardjd1725d12004-08-12 20:46:53 +00004853
sewardj9fc9e782004-11-26 17:57:40 +00004854 case 4: { /* FRSTOR m108 */
sewardj893aada2004-11-29 19:57:54 +00004855 /* Uses dirty helper:
4856 VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
4857 IRTemp ew = newTemp(Ity_I32);
4858 IRDirty* d = unsafeIRDirty_0_N (
4859 0/*regparms*/,
4860 "x86g_dirtyhelper_FRSTOR",
4861 &x86g_dirtyhelper_FRSTOR,
4862 mkIRExprVec_1( mkexpr(addr) )
4863 );
sewardj9fc9e782004-11-26 17:57:40 +00004864 d->needsBBP = True;
sewardj893aada2004-11-29 19:57:54 +00004865 d->tmp = ew;
sewardj9fc9e782004-11-26 17:57:40 +00004866 /* declare we're reading memory */
4867 d->mFx = Ifx_Read;
4868 d->mAddr = mkexpr(addr);
4869 d->mSize = 108;
4870
4871 /* declare we're writing guest state */
sewardj893aada2004-11-29 19:57:54 +00004872 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004873
4874 d->fxState[0].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004875 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004876 d->fxState[0].size = sizeof(UInt);
4877
4878 d->fxState[1].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004879 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004880 d->fxState[1].size = 8 * sizeof(ULong);
4881
4882 d->fxState[2].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004883 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004884 d->fxState[2].size = 8 * sizeof(UChar);
4885
4886 d->fxState[3].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004887 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004888 d->fxState[3].size = sizeof(UInt);
4889
4890 d->fxState[4].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004891 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004892 d->fxState[4].size = sizeof(UInt);
4893
4894 stmt( IRStmt_Dirty(d) );
4895
sewardj893aada2004-11-29 19:57:54 +00004896 /* ew contains any emulation warning we may need to
4897 issue. If needed, side-exit to the next insn,
4898 reporting the warning, so that Valgrind's dispatcher
4899 sees the warning. */
4900 put_emwarn( mkexpr(ew) );
4901 stmt(
4902 IRStmt_Exit(
4903 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4904 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004905 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj893aada2004-11-29 19:57:54 +00004906 )
4907 );
4908
sewardj33dd31b2005-01-08 18:17:32 +00004909 DIP("frstor %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00004910 break;
4911 }
4912
4913 case 6: { /* FNSAVE m108 */
sewardj893aada2004-11-29 19:57:54 +00004914 /* Uses dirty helper:
4915 void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
sewardj9fc9e782004-11-26 17:57:40 +00004916 IRDirty* d = unsafeIRDirty_0_N (
4917 0/*regparms*/,
4918 "x86g_dirtyhelper_FSAVE",
4919 &x86g_dirtyhelper_FSAVE,
4920 mkIRExprVec_1( mkexpr(addr) )
4921 );
4922 d->needsBBP = True;
4923 /* declare we're writing memory */
4924 d->mFx = Ifx_Write;
4925 d->mAddr = mkexpr(addr);
4926 d->mSize = 108;
4927
4928 /* declare we're reading guest state */
sewardj893aada2004-11-29 19:57:54 +00004929 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004930
4931 d->fxState[0].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004932 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004933 d->fxState[0].size = sizeof(UInt);
4934
4935 d->fxState[1].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004936 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004937 d->fxState[1].size = 8 * sizeof(ULong);
4938
4939 d->fxState[2].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004940 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004941 d->fxState[2].size = 8 * sizeof(UChar);
4942
4943 d->fxState[3].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004944 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004945 d->fxState[3].size = sizeof(UInt);
4946
4947 d->fxState[4].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004948 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004949 d->fxState[4].size = sizeof(UInt);
4950
4951 stmt( IRStmt_Dirty(d) );
4952
sewardj33dd31b2005-01-08 18:17:32 +00004953 DIP("fnsave %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00004954 break;
4955 }
4956
sewardjd24931d2005-03-20 12:51:39 +00004957 case 7: { /* FNSTSW m16 */
4958 IRExpr* sw = get_FPU_sw();
sewardjdd40fdf2006-12-24 02:20:24 +00004959 vassert(typeOfIRExpr(irsb->tyenv, sw) == Ity_I16);
sewardjd24931d2005-03-20 12:51:39 +00004960 storeLE( mkexpr(addr), sw );
4961 DIP("fnstsw %s\n", dis_buf);
4962 break;
4963 }
4964
sewardjd1725d12004-08-12 20:46:53 +00004965 default:
sewardjbb53f8c2004-08-14 11:50:01 +00004966 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4967 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00004968 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00004969 }
sewardjd1725d12004-08-12 20:46:53 +00004970 } else {
sewardja58ea662004-08-15 03:12:41 +00004971 delta++;
4972 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004973
sewardj3ddedc42005-03-25 20:30:00 +00004974 case 0xC0 ... 0xC7: /* FFREE %st(?) */
4975 r_dst = (UInt)modrm - 0xC0;
sewardj4a6f3842005-03-26 11:59:23 +00004976 DIP("ffree %%st(%d)\n", (Int)r_dst);
sewardj3ddedc42005-03-25 20:30:00 +00004977 put_ST_TAG ( r_dst, mkU8(0) );
4978 break;
4979
sewardj06c32a02004-09-12 12:07:34 +00004980 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
4981 r_dst = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004982 DIP("fst %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004983 /* P4 manual says: "If the destination operand is a
sewardj06c32a02004-09-12 12:07:34 +00004984 non-empty register, the invalid-operation exception
4985 is not generated. Hence put_ST_UNCHECKED. */
4986 put_ST_UNCHECKED(r_dst, get_ST(0));
4987 break;
4988
sewardja58ea662004-08-15 03:12:41 +00004989 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
4990 r_dst = (UInt)modrm - 0xD8;
sewardj2d49b432005-02-01 00:37:06 +00004991 DIP("fstp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004992 /* P4 manual says: "If the destination operand is a
sewardj207557a2004-08-27 12:00:18 +00004993 non-empty register, the invalid-operation exception
4994 is not generated. Hence put_ST_UNCHECKED. */
4995 put_ST_UNCHECKED(r_dst, get_ST(0));
4996 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004997 break;
sewardjbdc7d212004-09-09 02:46:40 +00004998
4999 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5000 r_dst = (UInt)modrm - 0xE0;
sewardj2d49b432005-02-01 00:37:06 +00005001 DIP("fucom %%st(0),%%st(%d)\n", (Int)r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00005002 /* This forces C1 to zero, which isn't right. */
5003 put_C3210(
5004 binop( Iop_And32,
5005 binop(Iop_Shl32,
5006 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5007 mkU8(8)),
5008 mkU32(0x4500)
5009 ));
sewardjbdc7d212004-09-09 02:46:40 +00005010 break;
5011
5012 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5013 r_dst = (UInt)modrm - 0xE8;
sewardj2d49b432005-02-01 00:37:06 +00005014 DIP("fucomp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00005015 /* This forces C1 to zero, which isn't right. */
5016 put_C3210(
5017 binop( Iop_And32,
5018 binop(Iop_Shl32,
5019 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5020 mkU8(8)),
5021 mkU32(0x4500)
5022 ));
sewardjbdc7d212004-09-09 02:46:40 +00005023 fp_pop();
5024 break;
5025
sewardj5bd4d162004-11-10 13:02:48 +00005026 default:
sewardja58ea662004-08-15 03:12:41 +00005027 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005028 }
sewardjd1725d12004-08-12 20:46:53 +00005029 }
5030 }
5031
5032 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5033 else
5034 if (first_opcode == 0xDE) {
sewardjbdc7d212004-09-09 02:46:40 +00005035
5036 if (modrm < 0xC0) {
sewardjfeeb8a82004-11-30 12:30:11 +00005037
5038 /* bits 5,4,3 are an opcode extension, and the modRM also
5039 specifies an address. */
5040 IROp fop;
5041 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5042 delta += len;
5043
5044 switch (gregOfRM(modrm)) {
5045
5046 case 0: /* FIADD m16int */ /* ST(0) += m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005047 DIP("fiaddw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005048 fop = Iop_AddF64;
5049 goto do_fop_m16;
5050
5051 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005052 DIP("fimulw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005053 fop = Iop_MulF64;
5054 goto do_fop_m16;
5055
sewardj071895f2005-07-29 11:28:38 +00005056 case 2: /* FICOM m16int */
5057 DIP("ficomw %s\n", dis_buf);
5058 /* This forces C1 to zero, which isn't right. */
5059 put_C3210(
5060 binop( Iop_And32,
5061 binop(Iop_Shl32,
5062 binop(Iop_CmpF64,
5063 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005064 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00005065 unop(Iop_16Sto32,
5066 loadLE(Ity_I16,mkexpr(addr))))),
5067 mkU8(8)),
5068 mkU32(0x4500)
5069 ));
5070 break;
5071
5072 case 3: /* FICOMP m16int */
5073 DIP("ficompw %s\n", dis_buf);
5074 /* This forces C1 to zero, which isn't right. */
5075 put_C3210(
5076 binop( Iop_And32,
5077 binop(Iop_Shl32,
5078 binop(Iop_CmpF64,
5079 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005080 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00005081 unop(Iop_16Sto32,
sewardjf1b5b1a2006-02-03 22:54:17 +00005082 loadLE(Ity_I16,mkexpr(addr))))),
sewardj071895f2005-07-29 11:28:38 +00005083 mkU8(8)),
5084 mkU32(0x4500)
5085 ));
5086 fp_pop();
5087 break;
5088
sewardjfeeb8a82004-11-30 12:30:11 +00005089 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005090 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005091 fop = Iop_SubF64;
5092 goto do_fop_m16;
5093
5094 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00005095 DIP("fisubrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005096 fop = Iop_SubF64;
5097 goto do_foprev_m16;
5098
5099 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005100 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005101 fop = Iop_DivF64;
5102 goto do_fop_m16;
5103
5104 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00005105 DIP("fidivrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005106 fop = Iop_DivF64;
5107 goto do_foprev_m16;
5108
5109 do_fop_m16:
5110 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00005111 triop(fop,
5112 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardjfeeb8a82004-11-30 12:30:11 +00005113 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005114 unop(Iop_I32StoF64,
sewardjfeeb8a82004-11-30 12:30:11 +00005115 unop(Iop_16Sto32,
5116 loadLE(Ity_I16, mkexpr(addr))))));
5117 break;
5118
5119 do_foprev_m16:
5120 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00005121 triop(fop,
5122 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6c299f32009-12-31 18:00:12 +00005123 unop(Iop_I32StoF64,
sewardjfeeb8a82004-11-30 12:30:11 +00005124 unop(Iop_16Sto32,
5125 loadLE(Ity_I16, mkexpr(addr)))),
5126 get_ST(0)));
5127 break;
5128
5129 default:
5130 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5131 vex_printf("first_opcode == 0xDE\n");
5132 goto decode_fail;
5133 }
sewardjbdc7d212004-09-09 02:46:40 +00005134
5135 } else {
5136
5137 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00005138 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00005139
sewardjcfded9a2004-09-09 11:44:16 +00005140 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5141 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5142 break;
5143
sewardjbdc7d212004-09-09 02:46:40 +00005144 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5145 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5146 break;
5147
sewardje166ed02004-10-25 02:27:01 +00005148 case 0xD9: /* FCOMPP %st(0),%st(1) */
5149 DIP("fuompp %%st(0),%%st(1)\n");
5150 /* This forces C1 to zero, which isn't right. */
5151 put_C3210(
5152 binop( Iop_And32,
5153 binop(Iop_Shl32,
5154 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5155 mkU8(8)),
5156 mkU32(0x4500)
5157 ));
5158 fp_pop();
5159 fp_pop();
5160 break;
5161
sewardjcfded9a2004-09-09 11:44:16 +00005162 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5163 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
5164 break;
5165
sewardj3fd5e572004-09-09 22:43:51 +00005166 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
5167 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
5168 break;
5169
sewardjbdc7d212004-09-09 02:46:40 +00005170 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5171 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5172 break;
5173
5174 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5175 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5176 break;
5177
5178 default:
5179 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005180 }
sewardjbdc7d212004-09-09 02:46:40 +00005181
5182 }
sewardjd1725d12004-08-12 20:46:53 +00005183 }
5184
5185 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5186 else
5187 if (first_opcode == 0xDF) {
sewardj89cd0932004-09-08 18:23:25 +00005188
5189 if (modrm < 0xC0) {
5190
sewardjfeeb8a82004-11-30 12:30:11 +00005191 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00005192 specifies an address. */
5193 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5194 delta += len;
5195
5196 switch (gregOfRM(modrm)) {
5197
sewardj883b00b2004-09-11 09:30:24 +00005198 case 0: /* FILD m16int */
5199 DIP("fildw %s\n", dis_buf);
5200 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00005201 put_ST(0, unop(Iop_I32StoF64,
sewardj883b00b2004-09-11 09:30:24 +00005202 unop(Iop_16Sto32,
5203 loadLE(Ity_I16, mkexpr(addr)))));
5204 break;
5205
sewardjdd5d2042006-08-03 15:03:19 +00005206 case 1: /* FISTTPS m16 (SSE3) */
5207 DIP("fisttps %s\n", dis_buf);
5208 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005209 binop(Iop_F64toI16S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjdd5d2042006-08-03 15:03:19 +00005210 fp_pop();
5211 break;
5212
sewardj37158712004-10-15 21:23:12 +00005213 case 2: /* FIST m16 */
sewardj33dd31b2005-01-08 18:17:32 +00005214 DIP("fistp %s\n", dis_buf);
sewardj37158712004-10-15 21:23:12 +00005215 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005216 binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
sewardj37158712004-10-15 21:23:12 +00005217 break;
5218
sewardj89cd0932004-09-08 18:23:25 +00005219 case 3: /* FISTP m16 */
sewardj33dd31b2005-01-08 18:17:32 +00005220 DIP("fistps %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00005221 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005222 binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
sewardj8f3debf2004-09-08 23:42:23 +00005223 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00005224 break;
5225
sewardj89cd0932004-09-08 18:23:25 +00005226 case 5: /* FILD m64 */
5227 DIP("fildll %s\n", dis_buf);
5228 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00005229 put_ST(0, binop(Iop_I64StoF64,
sewardj4cb918d2004-12-03 19:43:31 +00005230 get_roundingmode(),
5231 loadLE(Ity_I64, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00005232 break;
sewardj89cd0932004-09-08 18:23:25 +00005233
sewardjcfded9a2004-09-09 11:44:16 +00005234 case 7: /* FISTP m64 */
sewardj33dd31b2005-01-08 18:17:32 +00005235 DIP("fistpll %s\n", dis_buf);
sewardjcfded9a2004-09-09 11:44:16 +00005236 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005237 binop(Iop_F64toI64S, get_roundingmode(), get_ST(0)) );
sewardjcfded9a2004-09-09 11:44:16 +00005238 fp_pop();
5239 break;
5240
sewardj89cd0932004-09-08 18:23:25 +00005241 default:
5242 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5243 vex_printf("first_opcode == 0xDF\n");
5244 goto decode_fail;
5245 }
5246
5247 } else {
sewardjbdc7d212004-09-09 02:46:40 +00005248
5249 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00005250 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00005251
sewardj8fb88692005-07-29 11:57:00 +00005252 case 0xC0: /* FFREEP %st(0) */
5253 DIP("ffreep %%st(%d)\n", 0);
5254 put_ST_TAG ( 0, mkU8(0) );
5255 fp_pop();
5256 break;
5257
sewardjbdc7d212004-09-09 02:46:40 +00005258 case 0xE0: /* FNSTSW %ax */
5259 DIP("fnstsw %%ax\n");
sewardjd24931d2005-03-20 12:51:39 +00005260 /* Get the FPU status word value and dump it in %AX. */
sewardj1d2e77f2008-06-04 09:10:38 +00005261 if (0) {
5262 /* The obvious thing to do is simply dump the 16-bit
5263 status word value in %AX. However, due to a
5264 limitation in Memcheck's origin tracking
5265 machinery, this causes Memcheck not to track the
5266 origin of any undefinedness into %AH (only into
5267 %AL/%AX/%EAX), which means origins are lost in
5268 the sequence "fnstsw %ax; test $M,%ah; jcond .." */
5269 putIReg(2, R_EAX, get_FPU_sw());
5270 } else {
5271 /* So a somewhat lame kludge is to make it very
5272 clear to Memcheck that the value is written to
5273 both %AH and %AL. This generates marginally
5274 worse code, but I don't think it matters much. */
5275 IRTemp t16 = newTemp(Ity_I16);
5276 assign(t16, get_FPU_sw());
5277 putIReg( 1, R_AL, unop(Iop_16to8, mkexpr(t16)) );
5278 putIReg( 1, R_AH, unop(Iop_16HIto8, mkexpr(t16)) );
5279 }
sewardjbdc7d212004-09-09 02:46:40 +00005280 break;
5281
sewardj883b00b2004-09-11 09:30:24 +00005282 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
sewardj8308aad2004-09-12 11:09:54 +00005283 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
sewardj883b00b2004-09-11 09:30:24 +00005284 break;
5285
sewardjfeeb8a82004-11-30 12:30:11 +00005286 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5287 /* not really right since COMIP != UCOMIP */
5288 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5289 break;
5290
sewardjbdc7d212004-09-09 02:46:40 +00005291 default:
5292 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005293 }
sewardj89cd0932004-09-08 18:23:25 +00005294 }
5295
sewardjd1725d12004-08-12 20:46:53 +00005296 }
5297
5298 else
5299 vpanic("dis_FPU(x86): invalid primary opcode");
5300
sewardj69d9d662004-10-14 21:58:52 +00005301 *decode_ok = True;
5302 return delta;
5303
sewardjd1725d12004-08-12 20:46:53 +00005304 decode_fail:
5305 *decode_ok = False;
5306 return delta;
5307}
5308
5309
sewardj464efa42004-11-19 22:17:29 +00005310/*------------------------------------------------------------*/
5311/*--- ---*/
5312/*--- MMX INSTRUCTIONS ---*/
5313/*--- ---*/
5314/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00005315
sewardj464efa42004-11-19 22:17:29 +00005316/* Effect of MMX insns on x87 FPU state (table 11-2 of
5317 IA32 arch manual, volume 3):
5318
5319 Read from, or write to MMX register (viz, any insn except EMMS):
5320 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5321 * FP stack pointer set to zero
5322
5323 EMMS:
5324 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5325 * FP stack pointer set to zero
5326*/
5327
sewardj4cb918d2004-12-03 19:43:31 +00005328static void do_MMX_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00005329{
sewardjdd40fdf2006-12-24 02:20:24 +00005330 Int i;
5331 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5332 IRExpr* zero = mkU32(0);
5333 IRExpr* tag1 = mkU8(1);
sewardj464efa42004-11-19 22:17:29 +00005334 put_ftop(zero);
5335 for (i = 0; i < 8; i++)
5336 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
5337}
5338
sewardj4cb918d2004-12-03 19:43:31 +00005339static void do_EMMS_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00005340{
sewardjdd40fdf2006-12-24 02:20:24 +00005341 Int i;
5342 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5343 IRExpr* zero = mkU32(0);
5344 IRExpr* tag0 = mkU8(0);
sewardj464efa42004-11-19 22:17:29 +00005345 put_ftop(zero);
5346 for (i = 0; i < 8; i++)
5347 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
5348}
5349
5350
5351static IRExpr* getMMXReg ( UInt archreg )
5352{
5353 vassert(archreg < 8);
5354 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5355}
5356
5357
5358static void putMMXReg ( UInt archreg, IRExpr* e )
5359{
5360 vassert(archreg < 8);
sewardjdd40fdf2006-12-24 02:20:24 +00005361 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00005362 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5363}
5364
5365
sewardj38a3f862005-01-13 15:06:51 +00005366/* Helper for non-shift MMX insns. Note this is incomplete in the
5367 sense that it does not first call do_MMX_preamble() -- that is the
5368 responsibility of its caller. */
5369
sewardj464efa42004-11-19 22:17:29 +00005370static
sewardj2d49b432005-02-01 00:37:06 +00005371UInt dis_MMXop_regmem_to_reg ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00005372 Int delta,
sewardj2d49b432005-02-01 00:37:06 +00005373 UChar opc,
5374 HChar* name,
5375 Bool show_granularity )
sewardj464efa42004-11-19 22:17:29 +00005376{
sewardjc9a43662004-11-30 18:51:59 +00005377 HChar dis_buf[50];
sewardj63ba4092004-11-21 12:30:18 +00005378 UChar modrm = getIByte(delta);
5379 Bool isReg = epartIsReg(modrm);
5380 IRExpr* argL = NULL;
5381 IRExpr* argR = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005382 IRExpr* argG = NULL;
5383 IRExpr* argE = NULL;
sewardj63ba4092004-11-21 12:30:18 +00005384 IRTemp res = newTemp(Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00005385
sewardj38a3f862005-01-13 15:06:51 +00005386 Bool invG = False;
5387 IROp op = Iop_INVALID;
5388 void* hAddr = NULL;
sewardj2d49b432005-02-01 00:37:06 +00005389 HChar* hName = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005390 Bool eLeft = False;
5391
sewardj2b7a9202004-11-26 19:15:38 +00005392# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
sewardj464efa42004-11-19 22:17:29 +00005393
sewardj464efa42004-11-19 22:17:29 +00005394 switch (opc) {
sewardjb5452082004-12-04 20:33:02 +00005395 /* Original MMX ones */
sewardj38a3f862005-01-13 15:06:51 +00005396 case 0xFC: op = Iop_Add8x8; break;
5397 case 0xFD: op = Iop_Add16x4; break;
5398 case 0xFE: op = Iop_Add32x2; break;
sewardj464efa42004-11-19 22:17:29 +00005399
sewardj38a3f862005-01-13 15:06:51 +00005400 case 0xEC: op = Iop_QAdd8Sx8; break;
5401 case 0xED: op = Iop_QAdd16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00005402
sewardj38a3f862005-01-13 15:06:51 +00005403 case 0xDC: op = Iop_QAdd8Ux8; break;
5404 case 0xDD: op = Iop_QAdd16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00005405
sewardj38a3f862005-01-13 15:06:51 +00005406 case 0xF8: op = Iop_Sub8x8; break;
5407 case 0xF9: op = Iop_Sub16x4; break;
5408 case 0xFA: op = Iop_Sub32x2; break;
sewardj464efa42004-11-19 22:17:29 +00005409
sewardj38a3f862005-01-13 15:06:51 +00005410 case 0xE8: op = Iop_QSub8Sx8; break;
5411 case 0xE9: op = Iop_QSub16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00005412
sewardj38a3f862005-01-13 15:06:51 +00005413 case 0xD8: op = Iop_QSub8Ux8; break;
5414 case 0xD9: op = Iop_QSub16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00005415
sewardj38a3f862005-01-13 15:06:51 +00005416 case 0xE5: op = Iop_MulHi16Sx4; break;
5417 case 0xD5: op = Iop_Mul16x4; break;
5418 case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
sewardj4340dac2004-11-20 13:17:04 +00005419
sewardj38a3f862005-01-13 15:06:51 +00005420 case 0x74: op = Iop_CmpEQ8x8; break;
5421 case 0x75: op = Iop_CmpEQ16x4; break;
5422 case 0x76: op = Iop_CmpEQ32x2; break;
sewardj4340dac2004-11-20 13:17:04 +00005423
sewardj38a3f862005-01-13 15:06:51 +00005424 case 0x64: op = Iop_CmpGT8Sx8; break;
5425 case 0x65: op = Iop_CmpGT16Sx4; break;
5426 case 0x66: op = Iop_CmpGT32Sx2; break;
sewardj63ba4092004-11-21 12:30:18 +00005427
sewardj38a3f862005-01-13 15:06:51 +00005428 case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
5429 case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
5430 case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005431
sewardj38a3f862005-01-13 15:06:51 +00005432 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
5433 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
5434 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005435
sewardj38a3f862005-01-13 15:06:51 +00005436 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
5437 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
5438 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005439
sewardj38a3f862005-01-13 15:06:51 +00005440 case 0xDB: op = Iop_And64; break;
5441 case 0xDF: op = Iop_And64; invG = True; break;
5442 case 0xEB: op = Iop_Or64; break;
5443 case 0xEF: /* Possibly do better here if argL and argR are the
5444 same reg */
5445 op = Iop_Xor64; break;
sewardj464efa42004-11-19 22:17:29 +00005446
sewardjb5452082004-12-04 20:33:02 +00005447 /* Introduced in SSE1 */
sewardj38a3f862005-01-13 15:06:51 +00005448 case 0xE0: op = Iop_Avg8Ux8; break;
5449 case 0xE3: op = Iop_Avg16Ux4; break;
5450 case 0xEE: op = Iop_Max16Sx4; break;
5451 case 0xDE: op = Iop_Max8Ux8; break;
5452 case 0xEA: op = Iop_Min16Sx4; break;
5453 case 0xDA: op = Iop_Min8Ux8; break;
5454 case 0xE4: op = Iop_MulHi16Ux4; break;
5455 case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
sewardjb5452082004-12-04 20:33:02 +00005456
sewardj164f9272004-12-09 00:39:32 +00005457 /* Introduced in SSE2 */
sewardj38a3f862005-01-13 15:06:51 +00005458 case 0xD4: op = Iop_Add64; break;
5459 case 0xFB: op = Iop_Sub64; break;
sewardj164f9272004-12-09 00:39:32 +00005460
sewardj464efa42004-11-19 22:17:29 +00005461 default:
5462 vex_printf("\n0x%x\n", (Int)opc);
5463 vpanic("dis_MMXop_regmem_to_reg");
5464 }
5465
5466# undef XXX
5467
sewardj38a3f862005-01-13 15:06:51 +00005468 argG = getMMXReg(gregOfRM(modrm));
5469 if (invG)
5470 argG = unop(Iop_Not64, argG);
sewardj63ba4092004-11-21 12:30:18 +00005471
sewardj464efa42004-11-19 22:17:29 +00005472 if (isReg) {
sewardj464efa42004-11-19 22:17:29 +00005473 delta++;
sewardj38a3f862005-01-13 15:06:51 +00005474 argE = getMMXReg(eregOfRM(modrm));
sewardj464efa42004-11-19 22:17:29 +00005475 } else {
5476 Int len;
5477 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5478 delta += len;
sewardj38a3f862005-01-13 15:06:51 +00005479 argE = loadLE(Ity_I64, mkexpr(addr));
sewardj464efa42004-11-19 22:17:29 +00005480 }
5481
sewardj38a3f862005-01-13 15:06:51 +00005482 if (eLeft) {
5483 argL = argE;
5484 argR = argG;
5485 } else {
5486 argL = argG;
5487 argR = argE;
5488 }
5489
5490 if (op != Iop_INVALID) {
5491 vassert(hName == NULL);
5492 vassert(hAddr == NULL);
5493 assign(res, binop(op, argL, argR));
5494 } else {
5495 vassert(hName != NULL);
5496 vassert(hAddr != NULL);
5497 assign( res,
5498 mkIRExprCCall(
5499 Ity_I64,
5500 0/*regparms*/, hName, hAddr,
5501 mkIRExprVec_2( argL, argR )
5502 )
5503 );
sewardj63ba4092004-11-21 12:30:18 +00005504 }
5505
5506 putMMXReg( gregOfRM(modrm), mkexpr(res) );
5507
sewardj464efa42004-11-19 22:17:29 +00005508 DIP("%s%s %s, %s\n",
sewardj2d49b432005-02-01 00:37:06 +00005509 name, show_granularity ? nameMMXGran(opc & 3) : "",
sewardj464efa42004-11-19 22:17:29 +00005510 ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5511 nameMMXReg(gregOfRM(modrm)) );
5512
5513 return delta;
5514}
5515
5516
sewardj38a3f862005-01-13 15:06:51 +00005517/* Vector by scalar shift of G by the amount specified at the bottom
5518 of E. This is a straight copy of dis_SSE_shiftG_byE. */
5519
sewardj52d04912005-07-03 00:52:48 +00005520static UInt dis_MMX_shiftG_byE ( UChar sorb, Int delta,
sewardj38a3f862005-01-13 15:06:51 +00005521 HChar* opname, IROp op )
5522{
5523 HChar dis_buf[50];
5524 Int alen, size;
5525 IRTemp addr;
5526 Bool shl, shr, sar;
5527 UChar rm = getIByte(delta);
5528 IRTemp g0 = newTemp(Ity_I64);
5529 IRTemp g1 = newTemp(Ity_I64);
5530 IRTemp amt = newTemp(Ity_I32);
5531 IRTemp amt8 = newTemp(Ity_I8);
5532
5533 if (epartIsReg(rm)) {
5534 assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
5535 DIP("%s %s,%s\n", opname,
5536 nameMMXReg(eregOfRM(rm)),
5537 nameMMXReg(gregOfRM(rm)) );
5538 delta++;
5539 } else {
5540 addr = disAMode ( &alen, sorb, delta, dis_buf );
5541 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
5542 DIP("%s %s,%s\n", opname,
5543 dis_buf,
5544 nameMMXReg(gregOfRM(rm)) );
5545 delta += alen;
5546 }
5547 assign( g0, getMMXReg(gregOfRM(rm)) );
5548 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
5549
5550 shl = shr = sar = False;
5551 size = 0;
5552 switch (op) {
5553 case Iop_ShlN16x4: shl = True; size = 32; break;
5554 case Iop_ShlN32x2: shl = True; size = 32; break;
5555 case Iop_Shl64: shl = True; size = 64; break;
5556 case Iop_ShrN16x4: shr = True; size = 16; break;
5557 case Iop_ShrN32x2: shr = True; size = 32; break;
5558 case Iop_Shr64: shr = True; size = 64; break;
5559 case Iop_SarN16x4: sar = True; size = 16; break;
5560 case Iop_SarN32x2: sar = True; size = 32; break;
5561 default: vassert(0);
5562 }
5563
5564 if (shl || shr) {
5565 assign(
5566 g1,
5567 IRExpr_Mux0X(
5568 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5569 mkU64(0),
5570 binop(op, mkexpr(g0), mkexpr(amt8))
5571 )
5572 );
5573 } else
5574 if (sar) {
5575 assign(
5576 g1,
5577 IRExpr_Mux0X(
5578 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5579 binop(op, mkexpr(g0), mkU8(size-1)),
5580 binop(op, mkexpr(g0), mkexpr(amt8))
5581 )
5582 );
5583 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005584 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005585 vassert(0);
5586 }
5587
5588 putMMXReg( gregOfRM(rm), mkexpr(g1) );
5589 return delta;
5590}
5591
5592
5593/* Vector by scalar shift of E by an immediate byte. This is a
5594 straight copy of dis_SSE_shiftE_imm. */
5595
5596static
sewardj52d04912005-07-03 00:52:48 +00005597UInt dis_MMX_shiftE_imm ( Int delta, HChar* opname, IROp op )
sewardj38a3f862005-01-13 15:06:51 +00005598{
5599 Bool shl, shr, sar;
5600 UChar rm = getIByte(delta);
5601 IRTemp e0 = newTemp(Ity_I64);
5602 IRTemp e1 = newTemp(Ity_I64);
5603 UChar amt, size;
5604 vassert(epartIsReg(rm));
5605 vassert(gregOfRM(rm) == 2
5606 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00005607 amt = getIByte(delta+1);
sewardj38a3f862005-01-13 15:06:51 +00005608 delta += 2;
5609 DIP("%s $%d,%s\n", opname,
5610 (Int)amt,
5611 nameMMXReg(eregOfRM(rm)) );
5612
5613 assign( e0, getMMXReg(eregOfRM(rm)) );
5614
5615 shl = shr = sar = False;
5616 size = 0;
5617 switch (op) {
5618 case Iop_ShlN16x4: shl = True; size = 16; break;
5619 case Iop_ShlN32x2: shl = True; size = 32; break;
5620 case Iop_Shl64: shl = True; size = 64; break;
5621 case Iop_SarN16x4: sar = True; size = 16; break;
5622 case Iop_SarN32x2: sar = True; size = 32; break;
5623 case Iop_ShrN16x4: shr = True; size = 16; break;
5624 case Iop_ShrN32x2: shr = True; size = 32; break;
5625 case Iop_Shr64: shr = True; size = 64; break;
5626 default: vassert(0);
5627 }
5628
5629 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00005630 assign( e1, amt >= size
5631 ? mkU64(0)
5632 : binop(op, mkexpr(e0), mkU8(amt))
5633 );
sewardj38a3f862005-01-13 15:06:51 +00005634 } else
5635 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00005636 assign( e1, amt >= size
5637 ? binop(op, mkexpr(e0), mkU8(size-1))
5638 : binop(op, mkexpr(e0), mkU8(amt))
5639 );
sewardj38a3f862005-01-13 15:06:51 +00005640 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005641 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005642 vassert(0);
5643 }
5644
5645 putMMXReg( eregOfRM(rm), mkexpr(e1) );
5646 return delta;
5647}
5648
5649
5650/* Completely handle all MMX instructions except emms. */
sewardj464efa42004-11-19 22:17:29 +00005651
5652static
sewardj52d04912005-07-03 00:52:48 +00005653UInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, Int delta )
sewardj464efa42004-11-19 22:17:29 +00005654{
5655 Int len;
5656 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005657 HChar dis_buf[50];
sewardj464efa42004-11-19 22:17:29 +00005658 UChar opc = getIByte(delta);
5659 delta++;
5660
sewardj4cb918d2004-12-03 19:43:31 +00005661 /* dis_MMX handles all insns except emms. */
5662 do_MMX_preamble();
sewardj464efa42004-11-19 22:17:29 +00005663
5664 switch (opc) {
5665
sewardj2b7a9202004-11-26 19:15:38 +00005666 case 0x6E:
5667 /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
sewardj9df271d2004-12-31 22:37:42 +00005668 if (sz != 4)
5669 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005670 modrm = getIByte(delta);
5671 if (epartIsReg(modrm)) {
5672 delta++;
5673 putMMXReg(
5674 gregOfRM(modrm),
5675 binop( Iop_32HLto64,
5676 mkU32(0),
5677 getIReg(4, eregOfRM(modrm)) ) );
5678 DIP("movd %s, %s\n",
5679 nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5680 } else {
5681 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5682 delta += len;
5683 putMMXReg(
5684 gregOfRM(modrm),
5685 binop( Iop_32HLto64,
5686 mkU32(0),
5687 loadLE(Ity_I32, mkexpr(addr)) ) );
5688 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
5689 }
5690 break;
5691
5692 case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
sewardj9df271d2004-12-31 22:37:42 +00005693 if (sz != 4)
5694 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005695 modrm = getIByte(delta);
5696 if (epartIsReg(modrm)) {
5697 delta++;
5698 putIReg( 4, eregOfRM(modrm),
5699 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5700 DIP("movd %s, %s\n",
5701 nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
5702 } else {
5703 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5704 delta += len;
5705 storeLE( mkexpr(addr),
5706 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5707 DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
5708 }
5709 break;
5710
sewardj464efa42004-11-19 22:17:29 +00005711 case 0x6F:
5712 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005713 if (sz != 4)
5714 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005715 modrm = getIByte(delta);
5716 if (epartIsReg(modrm)) {
5717 delta++;
5718 putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5719 DIP("movq %s, %s\n",
5720 nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5721 } else {
5722 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5723 delta += len;
5724 putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5725 DIP("movq %s, %s\n",
5726 dis_buf, nameMMXReg(gregOfRM(modrm)));
5727 }
5728 break;
5729
5730 case 0x7F:
5731 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj9df271d2004-12-31 22:37:42 +00005732 if (sz != 4)
5733 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005734 modrm = getIByte(delta);
5735 if (epartIsReg(modrm)) {
sewardj9ca26402005-10-03 02:44:01 +00005736 delta++;
5737 putMMXReg( eregOfRM(modrm), getMMXReg(gregOfRM(modrm)) );
5738 DIP("movq %s, %s\n",
5739 nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
sewardj464efa42004-11-19 22:17:29 +00005740 } else {
5741 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5742 delta += len;
sewardj893aada2004-11-29 19:57:54 +00005743 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
sewardj464efa42004-11-19 22:17:29 +00005744 DIP("mov(nt)q %s, %s\n",
5745 nameMMXReg(gregOfRM(modrm)), dis_buf);
5746 }
5747 break;
5748
sewardj4340dac2004-11-20 13:17:04 +00005749 case 0xFC:
5750 case 0xFD:
5751 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005752 if (sz != 4)
5753 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005754 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5755 break;
5756
sewardj4340dac2004-11-20 13:17:04 +00005757 case 0xEC:
5758 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005759 if (sz != 4)
5760 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005761 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5762 break;
5763
sewardj4340dac2004-11-20 13:17:04 +00005764 case 0xDC:
5765 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005766 if (sz != 4)
5767 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005768 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5769 break;
5770
sewardj4340dac2004-11-20 13:17:04 +00005771 case 0xF8:
5772 case 0xF9:
5773 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005774 if (sz != 4)
5775 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005776 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
5777 break;
5778
sewardj4340dac2004-11-20 13:17:04 +00005779 case 0xE8:
5780 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005781 if (sz != 4)
5782 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005783 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5784 break;
5785
sewardj4340dac2004-11-20 13:17:04 +00005786 case 0xD8:
5787 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005788 if (sz != 4)
5789 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005790 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5791 break;
5792
5793 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005794 if (sz != 4)
5795 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005796 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5797 break;
5798
5799 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005800 if (sz != 4)
5801 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005802 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5803 break;
5804
sewardj4340dac2004-11-20 13:17:04 +00005805 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
5806 vassert(sz == 4);
5807 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
5808 break;
5809
5810 case 0x74:
5811 case 0x75:
5812 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005813 if (sz != 4)
5814 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00005815 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
5816 break;
5817
5818 case 0x64:
5819 case 0x65:
5820 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005821 if (sz != 4)
5822 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00005823 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
5824 break;
5825
sewardj63ba4092004-11-21 12:30:18 +00005826 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005827 if (sz != 4)
5828 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005829 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
5830 break;
5831
5832 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005833 if (sz != 4)
5834 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005835 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
5836 break;
5837
5838 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005839 if (sz != 4)
5840 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005841 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
5842 break;
5843
5844 case 0x68:
5845 case 0x69:
5846 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005847 if (sz != 4)
5848 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005849 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
5850 break;
5851
5852 case 0x60:
5853 case 0x61:
5854 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005855 if (sz != 4)
5856 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005857 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
5858 break;
5859
5860 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005861 if (sz != 4)
5862 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005863 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
5864 break;
5865
5866 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005867 if (sz != 4)
5868 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005869 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
5870 break;
5871
5872 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005873 if (sz != 4)
5874 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005875 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
5876 break;
5877
5878 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005879 if (sz != 4)
5880 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005881 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
sewardj38a3f862005-01-13 15:06:51 +00005882 break;
sewardj63ba4092004-11-21 12:30:18 +00005883
sewardj38a3f862005-01-13 15:06:51 +00005884# define SHIFT_BY_REG(_name,_op) \
5885 delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
5886 break;
sewardj8d14a592004-11-21 17:04:50 +00005887
sewardj38a3f862005-01-13 15:06:51 +00005888 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
5889 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
5890 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
5891 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
sewardj8d14a592004-11-21 17:04:50 +00005892
sewardj38a3f862005-01-13 15:06:51 +00005893 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
5894 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
5895 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
5896 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
5897
5898 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
5899 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
5900 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
5901
5902# undef SHIFT_BY_REG
sewardj8d14a592004-11-21 17:04:50 +00005903
sewardj2b7a9202004-11-26 19:15:38 +00005904 case 0x71:
5905 case 0x72:
5906 case 0x73: {
5907 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardja8415ff2005-01-21 20:55:36 +00005908 UChar byte2, subopc;
sewardj38a3f862005-01-13 15:06:51 +00005909 if (sz != 4)
5910 goto mmx_decode_failure;
sewardj38a3f862005-01-13 15:06:51 +00005911 byte2 = getIByte(delta); /* amode / sub-opcode */
sewardj9b45b482005-02-07 01:42:18 +00005912 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj2b7a9202004-11-26 19:15:38 +00005913
sewardj38a3f862005-01-13 15:06:51 +00005914# define SHIFT_BY_IMM(_name,_op) \
5915 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
5916 } while (0)
sewardj2b7a9202004-11-26 19:15:38 +00005917
sewardj2b7a9202004-11-26 19:15:38 +00005918 if (subopc == 2 /*SRL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005919 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005920 else if (subopc == 2 /*SRL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005921 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005922 else if (subopc == 2 /*SRL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00005923 SHIFT_BY_IMM("psrlq", Iop_Shr64);
sewardj2b7a9202004-11-26 19:15:38 +00005924
5925 else if (subopc == 4 /*SAR*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005926 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005927 else if (subopc == 4 /*SAR*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005928 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005929
5930 else if (subopc == 6 /*SHL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005931 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005932 else if (subopc == 6 /*SHL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005933 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005934 else if (subopc == 6 /*SHL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00005935 SHIFT_BY_IMM("psllq", Iop_Shl64);
sewardj2b7a9202004-11-26 19:15:38 +00005936
5937 else goto mmx_decode_failure;
5938
sewardj38a3f862005-01-13 15:06:51 +00005939# undef SHIFT_BY_IMM
sewardj2b7a9202004-11-26 19:15:38 +00005940 break;
5941 }
5942
sewardjd71ba832006-12-27 01:15:29 +00005943 case 0xF7: {
5944 IRTemp addr = newTemp(Ity_I32);
5945 IRTemp regD = newTemp(Ity_I64);
5946 IRTemp regM = newTemp(Ity_I64);
5947 IRTemp mask = newTemp(Ity_I64);
5948 IRTemp olddata = newTemp(Ity_I64);
5949 IRTemp newdata = newTemp(Ity_I64);
5950
5951 modrm = getIByte(delta);
5952 if (sz != 4 || (!epartIsReg(modrm)))
5953 goto mmx_decode_failure;
5954 delta++;
5955
5956 assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
5957 assign( regM, getMMXReg( eregOfRM(modrm) ));
5958 assign( regD, getMMXReg( gregOfRM(modrm) ));
5959 assign( mask, binop(Iop_SarN8x8, mkexpr(regM), mkU8(7)) );
5960 assign( olddata, loadLE( Ity_I64, mkexpr(addr) ));
5961 assign( newdata,
5962 binop(Iop_Or64,
5963 binop(Iop_And64,
5964 mkexpr(regD),
5965 mkexpr(mask) ),
5966 binop(Iop_And64,
5967 mkexpr(olddata),
5968 unop(Iop_Not64, mkexpr(mask)))) );
5969 storeLE( mkexpr(addr), mkexpr(newdata) );
5970 DIP("maskmovq %s,%s\n", nameMMXReg( eregOfRM(modrm) ),
5971 nameMMXReg( gregOfRM(modrm) ) );
5972 break;
5973 }
5974
sewardj2b7a9202004-11-26 19:15:38 +00005975 /* --- MMX decode failure --- */
sewardj464efa42004-11-19 22:17:29 +00005976 default:
sewardj2b7a9202004-11-26 19:15:38 +00005977 mmx_decode_failure:
sewardj464efa42004-11-19 22:17:29 +00005978 *decode_ok = False;
5979 return delta; /* ignored */
5980
5981 }
5982
5983 *decode_ok = True;
5984 return delta;
5985}
5986
5987
5988/*------------------------------------------------------------*/
5989/*--- More misc arithmetic and other obscure insns. ---*/
5990/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00005991
5992/* Double length left and right shifts. Apparently only required in
5993 v-size (no b- variant). */
5994static
5995UInt dis_SHLRD_Gv_Ev ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00005996 Int delta, UChar modrm,
sewardja06e5562004-07-14 13:18:05 +00005997 Int sz,
5998 IRExpr* shift_amt,
5999 Bool amt_is_literal,
sewardj2d49b432005-02-01 00:37:06 +00006000 HChar* shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00006001 Bool left_shift )
6002{
6003 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
6004 for printing it. And eip on entry points at the modrm byte. */
6005 Int len;
sewardjc9a43662004-11-30 18:51:59 +00006006 HChar dis_buf[50];
sewardja06e5562004-07-14 13:18:05 +00006007
sewardj6d2638e2004-07-15 09:38:27 +00006008 IRType ty = szToITy(sz);
6009 IRTemp gsrc = newTemp(ty);
6010 IRTemp esrc = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00006011 IRTemp addr = IRTemp_INVALID;
sewardj6d2638e2004-07-15 09:38:27 +00006012 IRTemp tmpSH = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00006013 IRTemp tmpL = IRTemp_INVALID;
6014 IRTemp tmpRes = IRTemp_INVALID;
6015 IRTemp tmpSubSh = IRTemp_INVALID;
sewardja06e5562004-07-14 13:18:05 +00006016 IROp mkpair;
6017 IROp getres;
6018 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00006019 IRExpr* mask = NULL;
6020
6021 vassert(sz == 2 || sz == 4);
6022
6023 /* The E-part is the destination; this is shifted. The G-part
6024 supplies bits to be shifted into the E-part, but is not
6025 changed.
6026
6027 If shifting left, form a double-length word with E at the top
6028 and G at the bottom, and shift this left. The result is then in
6029 the high part.
6030
6031 If shifting right, form a double-length word with G at the top
6032 and E at the bottom, and shift this right. The result is then
6033 at the bottom. */
6034
6035 /* Fetch the operands. */
6036
6037 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
6038
6039 if (epartIsReg(modrm)) {
6040 delta++;
6041 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00006042 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00006043 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00006044 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00006045 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
6046 } else {
6047 addr = disAMode ( &len, sorb, delta, dis_buf );
6048 delta += len;
6049 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00006050 DIP("sh%cd%c %s, %s, %s\n",
6051 ( left_shift ? 'l' : 'r' ), nameISize(sz),
6052 shift_amt_txt,
6053 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00006054 }
6055
6056 /* Round up the relevant primops. */
6057
6058 if (sz == 4) {
6059 tmpL = newTemp(Ity_I64);
6060 tmpRes = newTemp(Ity_I32);
6061 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00006062 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00006063 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00006064 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
6065 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00006066 } else {
6067 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00006068 tmpL = newTemp(Ity_I32);
6069 tmpRes = newTemp(Ity_I16);
6070 tmpSubSh = newTemp(Ity_I16);
6071 mkpair = Iop_16HLto32;
6072 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
6073 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
6074 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00006075 }
6076
6077 /* Do the shift, calculate the subshift value, and set
6078 the flag thunk. */
6079
sewardj8c7f1ab2004-07-29 20:31:09 +00006080 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
6081
sewardja06e5562004-07-14 13:18:05 +00006082 if (left_shift)
6083 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
6084 else
6085 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
6086
6087 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
6088 assign( tmpSubSh,
6089 unop(getres,
6090 binop(shift,
6091 mkexpr(tmpL),
6092 binop(Iop_And8,
6093 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6094 mask))) );
sewardja06e5562004-07-14 13:18:05 +00006095
sewardj2a2ba8b2004-11-08 13:14:06 +00006096 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
6097 tmpRes, tmpSubSh, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00006098
6099 /* Put result back. */
6100
6101 if (epartIsReg(modrm)) {
6102 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
6103 } else {
6104 storeLE( mkexpr(addr), mkexpr(tmpRes) );
6105 }
6106
6107 if (amt_is_literal) delta++;
6108 return delta;
6109}
6110
6111
sewardj1c6f9912004-09-07 10:15:24 +00006112/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
6113 required. */
6114
6115typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
6116
sewardj2d49b432005-02-01 00:37:06 +00006117static HChar* nameBtOp ( BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00006118{
6119 switch (op) {
6120 case BtOpNone: return "";
6121 case BtOpSet: return "s";
6122 case BtOpReset: return "r";
6123 case BtOpComp: return "c";
6124 default: vpanic("nameBtOp(x86)");
6125 }
6126}
6127
6128
6129static
sewardje9d8a262009-07-01 08:06:34 +00006130UInt dis_bt_G_E ( UChar sorb, Bool locked, Int sz, Int delta, BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00006131{
sewardjc9a43662004-11-30 18:51:59 +00006132 HChar dis_buf[50];
sewardj1c6f9912004-09-07 10:15:24 +00006133 UChar modrm;
6134 Int len;
6135 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
sewardje9d8a262009-07-01 08:06:34 +00006136 t_addr1, t_esp, t_mask, t_new;
sewardj1c6f9912004-09-07 10:15:24 +00006137
6138 vassert(sz == 2 || sz == 4);
6139
6140 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
sewardje9d8a262009-07-01 08:06:34 +00006141 = t_addr0 = t_addr1 = t_esp
6142 = t_mask = t_new = IRTemp_INVALID;
sewardj1c6f9912004-09-07 10:15:24 +00006143
6144 t_fetched = newTemp(Ity_I8);
sewardje9d8a262009-07-01 08:06:34 +00006145 t_new = newTemp(Ity_I8);
sewardj1c6f9912004-09-07 10:15:24 +00006146 t_bitno0 = newTemp(Ity_I32);
6147 t_bitno1 = newTemp(Ity_I32);
6148 t_bitno2 = newTemp(Ity_I8);
6149 t_addr1 = newTemp(Ity_I32);
6150 modrm = getIByte(delta);
6151
sewardj9ed16802005-08-24 10:46:19 +00006152 assign( t_bitno0, widenSto32(getIReg(sz, gregOfRM(modrm))) );
sewardj1c6f9912004-09-07 10:15:24 +00006153
6154 if (epartIsReg(modrm)) {
sewardj1c6f9912004-09-07 10:15:24 +00006155 delta++;
6156 /* Get it onto the client's stack. */
6157 t_esp = newTemp(Ity_I32);
6158 t_addr0 = newTemp(Ity_I32);
6159
6160 assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6161 putIReg(4, R_ESP, mkexpr(t_esp));
6162
6163 storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
6164
6165 /* Make t_addr0 point at it. */
6166 assign( t_addr0, mkexpr(t_esp) );
6167
6168 /* Mask out upper bits of the shift amount, since we're doing a
6169 reg. */
6170 assign( t_bitno1, binop(Iop_And32,
6171 mkexpr(t_bitno0),
6172 mkU32(sz == 4 ? 31 : 15)) );
6173
6174 } else {
6175 t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
6176 delta += len;
6177 assign( t_bitno1, mkexpr(t_bitno0) );
6178 }
6179
6180 /* At this point: t_addr0 is the address being operated on. If it
6181 was a reg, we will have pushed it onto the client's stack.
6182 t_bitno1 is the bit number, suitably masked in the case of a
6183 reg. */
6184
6185 /* Now the main sequence. */
6186 assign( t_addr1,
6187 binop(Iop_Add32,
6188 mkexpr(t_addr0),
6189 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
6190
6191 /* t_addr1 now holds effective address */
6192
6193 assign( t_bitno2,
6194 unop(Iop_32to8,
6195 binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
6196
6197 /* t_bitno2 contains offset of bit within byte */
6198
6199 if (op != BtOpNone) {
6200 t_mask = newTemp(Ity_I8);
6201 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
6202 }
sewardj4963a422004-10-14 23:34:03 +00006203
sewardj1c6f9912004-09-07 10:15:24 +00006204 /* t_mask is now a suitable byte mask */
6205
6206 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
6207
6208 if (op != BtOpNone) {
6209 switch (op) {
sewardje9d8a262009-07-01 08:06:34 +00006210 case BtOpSet:
6211 assign( t_new,
6212 binop(Iop_Or8, mkexpr(t_fetched), mkexpr(t_mask)) );
sewardj1c6f9912004-09-07 10:15:24 +00006213 break;
sewardje9d8a262009-07-01 08:06:34 +00006214 case BtOpComp:
6215 assign( t_new,
6216 binop(Iop_Xor8, mkexpr(t_fetched), mkexpr(t_mask)) );
sewardj1c6f9912004-09-07 10:15:24 +00006217 break;
sewardje9d8a262009-07-01 08:06:34 +00006218 case BtOpReset:
6219 assign( t_new,
6220 binop(Iop_And8, mkexpr(t_fetched),
6221 unop(Iop_Not8, mkexpr(t_mask))) );
sewardj1c6f9912004-09-07 10:15:24 +00006222 break;
6223 default:
6224 vpanic("dis_bt_G_E(x86)");
6225 }
sewardje9d8a262009-07-01 08:06:34 +00006226 if (locked && !epartIsReg(modrm)) {
6227 casLE( mkexpr(t_addr1), mkexpr(t_fetched)/*expd*/,
6228 mkexpr(t_new)/*new*/,
6229 guest_EIP_curr_instr );
6230 } else {
6231 storeLE( mkexpr(t_addr1), mkexpr(t_new) );
6232 }
sewardj1c6f9912004-09-07 10:15:24 +00006233 }
6234
6235 /* Side effect done; now get selected bit into Carry flag */
sewardj2a2ba8b2004-11-08 13:14:06 +00006236 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00006237 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006238 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00006239 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00006240 OFFB_CC_DEP1,
sewardj1c6f9912004-09-07 10:15:24 +00006241 binop(Iop_And32,
6242 binop(Iop_Shr32,
6243 unop(Iop_8Uto32, mkexpr(t_fetched)),
sewardj5bd4d162004-11-10 13:02:48 +00006244 mkexpr(t_bitno2)),
6245 mkU32(1)))
sewardj1c6f9912004-09-07 10:15:24 +00006246 );
sewardja3b7e3a2005-04-05 01:54:19 +00006247 /* Set NDEP even though it isn't used. This makes redundant-PUT
6248 elimination of previous stores to this field work better. */
6249 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00006250
6251 /* Move reg operand from stack back to reg */
6252 if (epartIsReg(modrm)) {
6253 /* t_esp still points at it. */
sewardj4963a422004-10-14 23:34:03 +00006254 putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
sewardj1c6f9912004-09-07 10:15:24 +00006255 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(sz)) );
6256 }
6257
6258 DIP("bt%s%c %s, %s\n",
6259 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
6260 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
6261
6262 return delta;
6263}
sewardjce646f22004-08-31 23:55:54 +00006264
6265
6266
6267/* Handle BSF/BSR. Only v-size seems necessary. */
6268static
sewardj52d04912005-07-03 00:52:48 +00006269UInt dis_bs_E_G ( UChar sorb, Int sz, Int delta, Bool fwds )
sewardjce646f22004-08-31 23:55:54 +00006270{
6271 Bool isReg;
6272 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00006273 HChar dis_buf[50];
sewardjce646f22004-08-31 23:55:54 +00006274
6275 IRType ty = szToITy(sz);
6276 IRTemp src = newTemp(ty);
6277 IRTemp dst = newTemp(ty);
6278
6279 IRTemp src32 = newTemp(Ity_I32);
6280 IRTemp dst32 = newTemp(Ity_I32);
6281 IRTemp src8 = newTemp(Ity_I8);
6282
6283 vassert(sz == 4 || sz == 2);
sewardjce646f22004-08-31 23:55:54 +00006284
6285 modrm = getIByte(delta);
6286
6287 isReg = epartIsReg(modrm);
6288 if (isReg) {
6289 delta++;
6290 assign( src, getIReg(sz, eregOfRM(modrm)) );
6291 } else {
6292 Int len;
6293 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6294 delta += len;
6295 assign( src, loadLE(ty, mkexpr(addr)) );
6296 }
6297
6298 DIP("bs%c%c %s, %s\n",
6299 fwds ? 'f' : 'r', nameISize(sz),
6300 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
6301 nameIReg(sz, gregOfRM(modrm)));
6302
6303 /* Generate an 8-bit expression which is zero iff the
6304 original is zero, and nonzero otherwise */
6305 assign( src8,
6306 unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
6307 mkexpr(src), mkU(ty,0))) );
6308
6309 /* Flags: Z is 1 iff source value is zero. All others
6310 are undefined -- we force them to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00006311 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006312 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00006313 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00006314 OFFB_CC_DEP1,
sewardjce646f22004-08-31 23:55:54 +00006315 IRExpr_Mux0X( mkexpr(src8),
6316 /* src==0 */
sewardj2a9ad022004-11-25 02:46:58 +00006317 mkU32(X86G_CC_MASK_Z),
sewardjce646f22004-08-31 23:55:54 +00006318 /* src!=0 */
6319 mkU32(0)
6320 )
6321 ));
sewardja3b7e3a2005-04-05 01:54:19 +00006322 /* Set NDEP even though it isn't used. This makes redundant-PUT
6323 elimination of previous stores to this field work better. */
6324 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00006325
6326 /* Result: iff source value is zero, we can't use
6327 Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
6328 But anyway, Intel x86 semantics say the result is undefined in
6329 such situations. Hence handle the zero case specially. */
6330
6331 /* Bleh. What we compute:
6332
6333 bsf32: if src == 0 then 0 else Ctz32(src)
6334 bsr32: if src == 0 then 0 else 31 - Clz32(src)
6335
6336 bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
6337 bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
6338
6339 First, widen src to 32 bits if it is not already.
sewardj37158712004-10-15 21:23:12 +00006340
6341 Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
6342 dst register unchanged when src == 0. Hence change accordingly.
sewardjce646f22004-08-31 23:55:54 +00006343 */
6344 if (sz == 2)
6345 assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
6346 else
6347 assign( src32, mkexpr(src) );
6348
6349 /* The main computation, guarding against zero. */
6350 assign( dst32,
6351 IRExpr_Mux0X(
6352 mkexpr(src8),
sewardj37158712004-10-15 21:23:12 +00006353 /* src == 0 -- leave dst unchanged */
6354 widenUto32( getIReg( sz, gregOfRM(modrm) ) ),
sewardjce646f22004-08-31 23:55:54 +00006355 /* src != 0 */
6356 fwds ? unop(Iop_Ctz32, mkexpr(src32))
6357 : binop(Iop_Sub32,
6358 mkU32(31),
6359 unop(Iop_Clz32, mkexpr(src32)))
6360 )
6361 );
6362
6363 if (sz == 2)
6364 assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
6365 else
6366 assign( dst, mkexpr(dst32) );
6367
6368 /* dump result back */
6369 putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
6370
6371 return delta;
6372}
sewardj64e1d652004-07-12 14:00:46 +00006373
6374
6375static
6376void codegen_xchg_eAX_Reg ( Int sz, Int reg )
6377{
6378 IRType ty = szToITy(sz);
6379 IRTemp t1 = newTemp(ty);
6380 IRTemp t2 = newTemp(ty);
6381 vassert(sz == 2 || sz == 4);
6382 assign( t1, getIReg(sz, R_EAX) );
6383 assign( t2, getIReg(sz, reg) );
6384 putIReg( sz, R_EAX, mkexpr(t2) );
6385 putIReg( sz, reg, mkexpr(t1) );
6386 DIP("xchg%c %s, %s\n",
6387 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
6388}
6389
6390
sewardjbdc7d212004-09-09 02:46:40 +00006391static
6392void codegen_SAHF ( void )
6393{
6394 /* Set the flags to:
sewardj2a9ad022004-11-25 02:46:58 +00006395 (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
6396 | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6397 |X86G_CC_MASK_P|X86G_CC_MASK_C)
sewardjbdc7d212004-09-09 02:46:40 +00006398 */
sewardj2a9ad022004-11-25 02:46:58 +00006399 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6400 |X86G_CC_MASK_C|X86G_CC_MASK_P;
sewardjbdc7d212004-09-09 02:46:40 +00006401 IRTemp oldflags = newTemp(Ity_I32);
sewardj2a9ad022004-11-25 02:46:58 +00006402 assign( oldflags, mk_x86g_calculate_eflags_all() );
6403 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj905edbd2007-04-07 12:25:37 +00006404 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006405 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6406 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardjbdc7d212004-09-09 02:46:40 +00006407 binop(Iop_Or32,
sewardj2a9ad022004-11-25 02:46:58 +00006408 binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
sewardjbdc7d212004-09-09 02:46:40 +00006409 binop(Iop_And32,
6410 binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
6411 mkU32(mask_SZACP))
6412 )
6413 ));
sewardja3b7e3a2005-04-05 01:54:19 +00006414 /* Set NDEP even though it isn't used. This makes redundant-PUT
6415 elimination of previous stores to this field work better. */
6416 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjbdc7d212004-09-09 02:46:40 +00006417}
6418
6419
sewardj8dfdc8a2005-10-03 11:39:02 +00006420static
6421void codegen_LAHF ( void )
6422{
6423 /* AH <- EFLAGS(SF:ZF:0:AF:0:PF:1:CF) */
6424 IRExpr* eax_with_hole;
6425 IRExpr* new_byte;
6426 IRExpr* new_eax;
6427 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6428 |X86G_CC_MASK_C|X86G_CC_MASK_P;
6429
6430 IRTemp flags = newTemp(Ity_I32);
6431 assign( flags, mk_x86g_calculate_eflags_all() );
6432
6433 eax_with_hole
6434 = binop(Iop_And32, getIReg(4, R_EAX), mkU32(0xFFFF00FF));
6435 new_byte
6436 = binop(Iop_Or32, binop(Iop_And32, mkexpr(flags), mkU32(mask_SZACP)),
6437 mkU32(1<<1));
6438 new_eax
6439 = binop(Iop_Or32, eax_with_hole,
6440 binop(Iop_Shl32, new_byte, mkU8(8)));
6441 putIReg(4, R_EAX, new_eax);
6442}
6443
sewardj458a6f82004-08-25 12:46:02 +00006444
6445static
6446UInt dis_cmpxchg_G_E ( UChar sorb,
sewardje9d8a262009-07-01 08:06:34 +00006447 Bool locked,
sewardj458a6f82004-08-25 12:46:02 +00006448 Int size,
sewardj52d04912005-07-03 00:52:48 +00006449 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00006450{
sewardjc9a43662004-11-30 18:51:59 +00006451 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006452 Int len;
6453
6454 IRType ty = szToITy(size);
6455 IRTemp acc = newTemp(ty);
6456 IRTemp src = newTemp(ty);
6457 IRTemp dest = newTemp(ty);
6458 IRTemp dest2 = newTemp(ty);
6459 IRTemp acc2 = newTemp(ty);
6460 IRTemp cond8 = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00006461 IRTemp addr = IRTemp_INVALID;
sewardj458a6f82004-08-25 12:46:02 +00006462 UChar rm = getUChar(delta0);
6463
sewardje9d8a262009-07-01 08:06:34 +00006464 /* There are 3 cases to consider:
6465
6466 reg-reg: ignore any lock prefix, generate sequence based
6467 on Mux0X
6468
6469 reg-mem, not locked: ignore any lock prefix, generate sequence
6470 based on Mux0X
6471
6472 reg-mem, locked: use IRCAS
6473 */
sewardj458a6f82004-08-25 12:46:02 +00006474 if (epartIsReg(rm)) {
sewardje9d8a262009-07-01 08:06:34 +00006475 /* case 1 */
sewardj458a6f82004-08-25 12:46:02 +00006476 assign( dest, getIReg(size, eregOfRM(rm)) );
6477 delta0++;
sewardje9d8a262009-07-01 08:06:34 +00006478 assign( src, getIReg(size, gregOfRM(rm)) );
6479 assign( acc, getIReg(size, R_EAX) );
6480 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6481 assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
6482 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
6483 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
6484 putIReg(size, R_EAX, mkexpr(acc2));
6485 putIReg(size, eregOfRM(rm), mkexpr(dest2));
sewardj458a6f82004-08-25 12:46:02 +00006486 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6487 nameIReg(size,gregOfRM(rm)),
6488 nameIReg(size,eregOfRM(rm)) );
sewardje9d8a262009-07-01 08:06:34 +00006489 }
6490 else if (!epartIsReg(rm) && !locked) {
6491 /* case 2 */
sewardj458a6f82004-08-25 12:46:02 +00006492 addr = disAMode ( &len, sorb, delta0, dis_buf );
6493 assign( dest, loadLE(ty, mkexpr(addr)) );
6494 delta0 += len;
sewardje9d8a262009-07-01 08:06:34 +00006495 assign( src, getIReg(size, gregOfRM(rm)) );
6496 assign( acc, getIReg(size, R_EAX) );
6497 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6498 assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
6499 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
6500 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
6501 putIReg(size, R_EAX, mkexpr(acc2));
6502 storeLE( mkexpr(addr), mkexpr(dest2) );
sewardj458a6f82004-08-25 12:46:02 +00006503 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6504 nameIReg(size,gregOfRM(rm)), dis_buf);
6505 }
sewardje9d8a262009-07-01 08:06:34 +00006506 else if (!epartIsReg(rm) && locked) {
6507 /* case 3 */
6508 /* src is new value. acc is expected value. dest is old value.
6509 Compute success from the output of the IRCAS, and steer the
6510 new value for EAX accordingly: in case of success, EAX is
6511 unchanged. */
6512 addr = disAMode ( &len, sorb, delta0, dis_buf );
6513 delta0 += len;
6514 assign( src, getIReg(size, gregOfRM(rm)) );
6515 assign( acc, getIReg(size, R_EAX) );
6516 stmt( IRStmt_CAS(
6517 mkIRCAS( IRTemp_INVALID, dest, Iend_LE, mkexpr(addr),
6518 NULL, mkexpr(acc), NULL, mkexpr(src) )
6519 ));
6520 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6521 assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
6522 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
6523 putIReg(size, R_EAX, mkexpr(acc2));
sewardj40d1d212009-07-12 13:01:17 +00006524 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6525 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardj458a6f82004-08-25 12:46:02 +00006526 }
sewardje9d8a262009-07-01 08:06:34 +00006527 else vassert(0);
sewardj458a6f82004-08-25 12:46:02 +00006528
6529 return delta0;
6530}
6531
6532
sewardj458a6f82004-08-25 12:46:02 +00006533/* Handle conditional move instructions of the form
6534 cmovcc E(reg-or-mem), G(reg)
6535
6536 E(src) is reg-or-mem
6537 G(dst) is reg.
6538
6539 If E is reg, --> GET %E, tmps
6540 GET %G, tmpd
6541 CMOVcc tmps, tmpd
6542 PUT tmpd, %G
6543
6544 If E is mem --> (getAddr E) -> tmpa
6545 LD (tmpa), tmps
6546 GET %G, tmpd
6547 CMOVcc tmps, tmpd
6548 PUT tmpd, %G
6549*/
6550static
6551UInt dis_cmov_E_G ( UChar sorb,
6552 Int sz,
sewardj2a9ad022004-11-25 02:46:58 +00006553 X86Condcode cond,
sewardj52d04912005-07-03 00:52:48 +00006554 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00006555{
6556 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006557 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006558 Int len;
6559
sewardj883b00b2004-09-11 09:30:24 +00006560 IRType ty = szToITy(sz);
sewardj458a6f82004-08-25 12:46:02 +00006561 IRTemp tmps = newTemp(ty);
6562 IRTemp tmpd = newTemp(ty);
6563
6564 if (epartIsReg(rm)) {
6565 assign( tmps, getIReg(sz, eregOfRM(rm)) );
6566 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6567
6568 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006569 IRExpr_Mux0X( unop(Iop_1Uto8,
6570 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006571 mkexpr(tmpd),
6572 mkexpr(tmps) )
6573 );
6574 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006575 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006576 nameIReg(sz,eregOfRM(rm)),
6577 nameIReg(sz,gregOfRM(rm)));
6578 return 1+delta0;
6579 }
6580
6581 /* E refers to memory */
6582 {
6583 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6584 assign( tmps, loadLE(ty, mkexpr(addr)) );
6585 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6586
6587 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006588 IRExpr_Mux0X( unop(Iop_1Uto8,
6589 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006590 mkexpr(tmpd),
6591 mkexpr(tmps) )
6592 );
6593
6594 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006595 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006596 dis_buf,
6597 nameIReg(sz,gregOfRM(rm)));
6598 return len+delta0;
6599 }
6600}
6601
6602
sewardj883b00b2004-09-11 09:30:24 +00006603static
sewardje9d8a262009-07-01 08:06:34 +00006604UInt dis_xadd_G_E ( UChar sorb, Bool locked, Int sz, Int delta0,
6605 Bool* decodeOK )
sewardj883b00b2004-09-11 09:30:24 +00006606{
6607 Int len;
6608 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006609 HChar dis_buf[50];
sewardj883b00b2004-09-11 09:30:24 +00006610
sewardj883b00b2004-09-11 09:30:24 +00006611 IRType ty = szToITy(sz);
6612 IRTemp tmpd = newTemp(ty);
6613 IRTemp tmpt0 = newTemp(ty);
6614 IRTemp tmpt1 = newTemp(ty);
6615
sewardje9d8a262009-07-01 08:06:34 +00006616 /* There are 3 cases to consider:
6617
sewardjc2433a82010-05-10 20:51:22 +00006618 reg-reg: ignore any lock prefix,
6619 generate 'naive' (non-atomic) sequence
sewardje9d8a262009-07-01 08:06:34 +00006620
6621 reg-mem, not locked: ignore any lock prefix, generate 'naive'
6622 (non-atomic) sequence
6623
6624 reg-mem, locked: use IRCAS
6625 */
6626
sewardj883b00b2004-09-11 09:30:24 +00006627 if (epartIsReg(rm)) {
sewardje9d8a262009-07-01 08:06:34 +00006628 /* case 1 */
sewardjc2433a82010-05-10 20:51:22 +00006629 assign( tmpd, getIReg(sz, eregOfRM(rm)));
6630 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6631 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6632 mkexpr(tmpd), mkexpr(tmpt0)) );
6633 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6634 putIReg(sz, eregOfRM(rm), mkexpr(tmpt1));
6635 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6636 DIP("xadd%c %s, %s\n",
6637 nameISize(sz), nameIReg(sz,gregOfRM(rm)),
6638 nameIReg(sz,eregOfRM(rm)));
6639 *decodeOK = True;
6640 return 1+delta0;
sewardje9d8a262009-07-01 08:06:34 +00006641 }
6642 else if (!epartIsReg(rm) && !locked) {
6643 /* case 2 */
sewardj883b00b2004-09-11 09:30:24 +00006644 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6645 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6646 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
sewardje9d8a262009-07-01 08:06:34 +00006647 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6648 mkexpr(tmpd), mkexpr(tmpt0)) );
sewardj883b00b2004-09-11 09:30:24 +00006649 storeLE( mkexpr(addr), mkexpr(tmpt1) );
sewardje9d8a262009-07-01 08:06:34 +00006650 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
sewardj883b00b2004-09-11 09:30:24 +00006651 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6652 DIP("xadd%c %s, %s\n",
6653 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
sewardj0092e0d2006-03-06 13:35:42 +00006654 *decodeOK = True;
sewardj883b00b2004-09-11 09:30:24 +00006655 return len+delta0;
6656 }
sewardje9d8a262009-07-01 08:06:34 +00006657 else if (!epartIsReg(rm) && locked) {
6658 /* case 3 */
6659 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6660 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6661 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6662 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6663 mkexpr(tmpd), mkexpr(tmpt0)) );
6664 casLE( mkexpr(addr), mkexpr(tmpd)/*expVal*/,
6665 mkexpr(tmpt1)/*newVal*/, guest_EIP_curr_instr );
6666 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6667 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6668 DIP("xadd%c %s, %s\n",
6669 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6670 *decodeOK = True;
6671 return len+delta0;
6672 }
6673 /*UNREACHED*/
6674 vassert(0);
sewardj883b00b2004-09-11 09:30:24 +00006675}
6676
sewardjb64821b2004-12-14 10:00:16 +00006677/* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
6678
sewardj7df596b2004-12-06 14:29:12 +00006679static
sewardj52d04912005-07-03 00:52:48 +00006680UInt dis_mov_Ew_Sw ( UChar sorb, Int delta0 )
sewardj7df596b2004-12-06 14:29:12 +00006681{
sewardjb64821b2004-12-14 10:00:16 +00006682 Int len;
6683 IRTemp addr;
6684 UChar rm = getIByte(delta0);
6685 HChar dis_buf[50];
sewardj7df596b2004-12-06 14:29:12 +00006686
6687 if (epartIsReg(rm)) {
6688 putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
6689 DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
6690 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006691 } else {
6692 addr = disAMode ( &len, sorb, delta0, dis_buf );
6693 putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
6694 DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
6695 return len+delta0;
sewardj7df596b2004-12-06 14:29:12 +00006696 }
6697}
6698
sewardjb64821b2004-12-14 10:00:16 +00006699/* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
6700 dst is ireg and sz==4, zero out top half of it. */
6701
sewardj063f02f2004-10-20 12:36:12 +00006702static
6703UInt dis_mov_Sw_Ew ( UChar sorb,
6704 Int sz,
sewardj52d04912005-07-03 00:52:48 +00006705 Int delta0 )
sewardj063f02f2004-10-20 12:36:12 +00006706{
sewardjb64821b2004-12-14 10:00:16 +00006707 Int len;
6708 IRTemp addr;
6709 UChar rm = getIByte(delta0);
6710 HChar dis_buf[50];
sewardj063f02f2004-10-20 12:36:12 +00006711
6712 vassert(sz == 2 || sz == 4);
6713
6714 if (epartIsReg(rm)) {
6715 if (sz == 4)
6716 putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6717 else
6718 putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6719
6720 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6721 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006722 } else {
6723 addr = disAMode ( &len, sorb, delta0, dis_buf );
6724 storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
sewardj063f02f2004-10-20 12:36:12 +00006725 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
sewardjb64821b2004-12-14 10:00:16 +00006726 return len+delta0;
sewardj063f02f2004-10-20 12:36:12 +00006727 }
sewardj063f02f2004-10-20 12:36:12 +00006728}
6729
6730
sewardjb64821b2004-12-14 10:00:16 +00006731static
6732void dis_push_segreg ( UInt sreg, Int sz )
6733{
6734 IRTemp t1 = newTemp(Ity_I16);
6735 IRTemp ta = newTemp(Ity_I32);
6736 vassert(sz == 2 || sz == 4);
6737
6738 assign( t1, getSReg(sreg) );
6739 assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6740 putIReg(4, R_ESP, mkexpr(ta));
6741 storeLE( mkexpr(ta), mkexpr(t1) );
6742
sewardj5c5f72c2006-03-18 11:29:25 +00006743 DIP("push%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
sewardjb64821b2004-12-14 10:00:16 +00006744}
6745
6746static
6747void dis_pop_segreg ( UInt sreg, Int sz )
6748{
6749 IRTemp t1 = newTemp(Ity_I16);
6750 IRTemp ta = newTemp(Ity_I32);
6751 vassert(sz == 2 || sz == 4);
6752
6753 assign( ta, getIReg(4, R_ESP) );
6754 assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
6755
6756 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
6757 putSReg( sreg, mkexpr(t1) );
sewardj5c5f72c2006-03-18 11:29:25 +00006758 DIP("pop%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
sewardjb64821b2004-12-14 10:00:16 +00006759}
sewardje05c42c2004-07-08 20:25:10 +00006760
6761static
6762void dis_ret ( UInt d32 )
6763{
6764 IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
6765 assign(t1, getIReg(4,R_ESP));
6766 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6767 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardj78c19df2004-07-12 22:49:27 +00006768 jmp_treg(Ijk_Ret,t2);
sewardje05c42c2004-07-08 20:25:10 +00006769}
6770
sewardj4cb918d2004-12-03 19:43:31 +00006771/*------------------------------------------------------------*/
6772/*--- SSE/SSE2/SSE3 helpers ---*/
6773/*------------------------------------------------------------*/
sewardjc9a43662004-11-30 18:51:59 +00006774
sewardj129b3d92004-12-05 15:42:05 +00006775/* Worker function; do not call directly.
6776 Handles full width G = G `op` E and G = (not G) `op` E.
6777*/
6778
6779static UInt dis_SSE_E_to_G_all_wrk (
sewardj52d04912005-07-03 00:52:48 +00006780 UChar sorb, Int delta,
sewardj1e6ad742004-12-02 16:16:11 +00006781 HChar* opname, IROp op,
6782 Bool invertG
6783 )
sewardjc9a43662004-11-30 18:51:59 +00006784{
sewardj1e6ad742004-12-02 16:16:11 +00006785 HChar dis_buf[50];
6786 Int alen;
6787 IRTemp addr;
6788 UChar rm = getIByte(delta);
6789 IRExpr* gpart
sewardjf0c1c582005-02-07 23:47:38 +00006790 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRM(rm)))
sewardj1e6ad742004-12-02 16:16:11 +00006791 : getXMMReg(gregOfRM(rm));
sewardjc9a43662004-11-30 18:51:59 +00006792 if (epartIsReg(rm)) {
6793 putXMMReg( gregOfRM(rm),
sewardj1e6ad742004-12-02 16:16:11 +00006794 binop(op, gpart,
6795 getXMMReg(eregOfRM(rm))) );
sewardjc9a43662004-11-30 18:51:59 +00006796 DIP("%s %s,%s\n", opname,
6797 nameXMMReg(eregOfRM(rm)),
6798 nameXMMReg(gregOfRM(rm)) );
6799 return delta+1;
6800 } else {
sewardj1e6ad742004-12-02 16:16:11 +00006801 addr = disAMode ( &alen, sorb, delta, dis_buf );
6802 putXMMReg( gregOfRM(rm),
6803 binop(op, gpart,
6804 loadLE(Ity_V128, mkexpr(addr))) );
6805 DIP("%s %s,%s\n", opname,
6806 dis_buf,
6807 nameXMMReg(gregOfRM(rm)) );
6808 return delta+alen;
sewardjc9a43662004-11-30 18:51:59 +00006809 }
6810}
6811
sewardj129b3d92004-12-05 15:42:05 +00006812
6813/* All lanes SSE binary operation, G = G `op` E. */
sewardj1e6ad742004-12-02 16:16:11 +00006814
6815static
sewardj52d04912005-07-03 00:52:48 +00006816UInt dis_SSE_E_to_G_all ( UChar sorb, Int delta, HChar* opname, IROp op )
sewardj1e6ad742004-12-02 16:16:11 +00006817{
sewardj129b3d92004-12-05 15:42:05 +00006818 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
sewardj1e6ad742004-12-02 16:16:11 +00006819}
6820
sewardj129b3d92004-12-05 15:42:05 +00006821/* All lanes SSE binary operation, G = (not G) `op` E. */
6822
6823static
sewardj52d04912005-07-03 00:52:48 +00006824UInt dis_SSE_E_to_G_all_invG ( UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006825 HChar* opname, IROp op )
6826{
6827 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
6828}
6829
sewardj164f9272004-12-09 00:39:32 +00006830
sewardj129b3d92004-12-05 15:42:05 +00006831/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
6832
sewardj52d04912005-07-03 00:52:48 +00006833static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006834 HChar* opname, IROp op )
6835{
6836 HChar dis_buf[50];
6837 Int alen;
6838 IRTemp addr;
6839 UChar rm = getIByte(delta);
6840 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6841 if (epartIsReg(rm)) {
6842 putXMMReg( gregOfRM(rm),
6843 binop(op, gpart,
6844 getXMMReg(eregOfRM(rm))) );
6845 DIP("%s %s,%s\n", opname,
6846 nameXMMReg(eregOfRM(rm)),
6847 nameXMMReg(gregOfRM(rm)) );
6848 return delta+1;
6849 } else {
6850 /* We can only do a 32-bit memory read, so the upper 3/4 of the
6851 E operand needs to be made simply of zeroes. */
6852 IRTemp epart = newTemp(Ity_V128);
6853 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00006854 assign( epart, unop( Iop_32UtoV128,
sewardj129b3d92004-12-05 15:42:05 +00006855 loadLE(Ity_I32, mkexpr(addr))) );
6856 putXMMReg( gregOfRM(rm),
6857 binop(op, gpart, mkexpr(epart)) );
6858 DIP("%s %s,%s\n", opname,
6859 dis_buf,
6860 nameXMMReg(gregOfRM(rm)) );
6861 return delta+alen;
6862 }
6863}
6864
sewardj164f9272004-12-09 00:39:32 +00006865
sewardj636ad762004-12-07 11:16:04 +00006866/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
6867
sewardj52d04912005-07-03 00:52:48 +00006868static UInt dis_SSE_E_to_G_lo64 ( UChar sorb, Int delta,
sewardj636ad762004-12-07 11:16:04 +00006869 HChar* opname, IROp op )
6870{
6871 HChar dis_buf[50];
6872 Int alen;
6873 IRTemp addr;
6874 UChar rm = getIByte(delta);
6875 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6876 if (epartIsReg(rm)) {
6877 putXMMReg( gregOfRM(rm),
6878 binop(op, gpart,
6879 getXMMReg(eregOfRM(rm))) );
6880 DIP("%s %s,%s\n", opname,
6881 nameXMMReg(eregOfRM(rm)),
6882 nameXMMReg(gregOfRM(rm)) );
6883 return delta+1;
6884 } else {
6885 /* We can only do a 64-bit memory read, so the upper half of the
6886 E operand needs to be made simply of zeroes. */
6887 IRTemp epart = newTemp(Ity_V128);
6888 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00006889 assign( epart, unop( Iop_64UtoV128,
sewardj636ad762004-12-07 11:16:04 +00006890 loadLE(Ity_I64, mkexpr(addr))) );
6891 putXMMReg( gregOfRM(rm),
6892 binop(op, gpart, mkexpr(epart)) );
6893 DIP("%s %s,%s\n", opname,
6894 dis_buf,
6895 nameXMMReg(gregOfRM(rm)) );
6896 return delta+alen;
6897 }
6898}
6899
sewardj164f9272004-12-09 00:39:32 +00006900
sewardj129b3d92004-12-05 15:42:05 +00006901/* All lanes unary SSE operation, G = op(E). */
6902
6903static UInt dis_SSE_E_to_G_unary_all (
sewardj52d04912005-07-03 00:52:48 +00006904 UChar sorb, Int delta,
sewardj0bd7ce62004-12-05 02:47:40 +00006905 HChar* opname, IROp op
6906 )
6907{
6908 HChar dis_buf[50];
6909 Int alen;
6910 IRTemp addr;
6911 UChar rm = getIByte(delta);
6912 if (epartIsReg(rm)) {
6913 putXMMReg( gregOfRM(rm),
6914 unop(op, getXMMReg(eregOfRM(rm))) );
6915 DIP("%s %s,%s\n", opname,
6916 nameXMMReg(eregOfRM(rm)),
6917 nameXMMReg(gregOfRM(rm)) );
6918 return delta+1;
6919 } else {
6920 addr = disAMode ( &alen, sorb, delta, dis_buf );
6921 putXMMReg( gregOfRM(rm),
6922 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
6923 DIP("%s %s,%s\n", opname,
6924 dis_buf,
6925 nameXMMReg(gregOfRM(rm)) );
6926 return delta+alen;
6927 }
6928}
6929
sewardj164f9272004-12-09 00:39:32 +00006930
sewardj129b3d92004-12-05 15:42:05 +00006931/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
sewardj0bd7ce62004-12-05 02:47:40 +00006932
sewardj129b3d92004-12-05 15:42:05 +00006933static UInt dis_SSE_E_to_G_unary_lo32 (
sewardj52d04912005-07-03 00:52:48 +00006934 UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006935 HChar* opname, IROp op
6936 )
6937{
6938 /* First we need to get the old G value and patch the low 32 bits
6939 of the E operand into it. Then apply op and write back to G. */
6940 HChar dis_buf[50];
6941 Int alen;
6942 IRTemp addr;
6943 UChar rm = getIByte(delta);
6944 IRTemp oldG0 = newTemp(Ity_V128);
6945 IRTemp oldG1 = newTemp(Ity_V128);
6946
6947 assign( oldG0, getXMMReg(gregOfRM(rm)) );
6948
6949 if (epartIsReg(rm)) {
6950 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006951 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00006952 mkexpr(oldG0),
sewardj35579be2004-12-06 00:36:25 +00006953 getXMMRegLane32(eregOfRM(rm), 0)) );
sewardj129b3d92004-12-05 15:42:05 +00006954 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6955 DIP("%s %s,%s\n", opname,
6956 nameXMMReg(eregOfRM(rm)),
6957 nameXMMReg(gregOfRM(rm)) );
6958 return delta+1;
6959 } else {
6960 addr = disAMode ( &alen, sorb, delta, dis_buf );
6961 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006962 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00006963 mkexpr(oldG0),
6964 loadLE(Ity_I32, mkexpr(addr)) ));
6965 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6966 DIP("%s %s,%s\n", opname,
6967 dis_buf,
6968 nameXMMReg(gregOfRM(rm)) );
6969 return delta+alen;
6970 }
6971}
6972
sewardj164f9272004-12-09 00:39:32 +00006973
sewardj008754b2004-12-08 14:37:10 +00006974/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
6975
6976static UInt dis_SSE_E_to_G_unary_lo64 (
sewardj52d04912005-07-03 00:52:48 +00006977 UChar sorb, Int delta,
sewardj008754b2004-12-08 14:37:10 +00006978 HChar* opname, IROp op
6979 )
6980{
6981 /* First we need to get the old G value and patch the low 64 bits
6982 of the E operand into it. Then apply op and write back to G. */
6983 HChar dis_buf[50];
6984 Int alen;
6985 IRTemp addr;
6986 UChar rm = getIByte(delta);
6987 IRTemp oldG0 = newTemp(Ity_V128);
6988 IRTemp oldG1 = newTemp(Ity_V128);
6989
6990 assign( oldG0, getXMMReg(gregOfRM(rm)) );
6991
6992 if (epartIsReg(rm)) {
6993 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006994 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00006995 mkexpr(oldG0),
6996 getXMMRegLane64(eregOfRM(rm), 0)) );
6997 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6998 DIP("%s %s,%s\n", opname,
6999 nameXMMReg(eregOfRM(rm)),
7000 nameXMMReg(gregOfRM(rm)) );
7001 return delta+1;
7002 } else {
7003 addr = disAMode ( &alen, sorb, delta, dis_buf );
7004 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00007005 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00007006 mkexpr(oldG0),
7007 loadLE(Ity_I64, mkexpr(addr)) ));
7008 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7009 DIP("%s %s,%s\n", opname,
7010 dis_buf,
7011 nameXMMReg(gregOfRM(rm)) );
7012 return delta+alen;
7013 }
7014}
7015
sewardj164f9272004-12-09 00:39:32 +00007016
7017/* SSE integer binary operation:
7018 G = G `op` E (eLeft == False)
7019 G = E `op` G (eLeft == True)
7020*/
7021static UInt dis_SSEint_E_to_G(
sewardj52d04912005-07-03 00:52:48 +00007022 UChar sorb, Int delta,
sewardj164f9272004-12-09 00:39:32 +00007023 HChar* opname, IROp op,
7024 Bool eLeft
7025 )
7026{
7027 HChar dis_buf[50];
7028 Int alen;
7029 IRTemp addr;
7030 UChar rm = getIByte(delta);
7031 IRExpr* gpart = getXMMReg(gregOfRM(rm));
7032 IRExpr* epart = NULL;
7033 if (epartIsReg(rm)) {
7034 epart = getXMMReg(eregOfRM(rm));
7035 DIP("%s %s,%s\n", opname,
7036 nameXMMReg(eregOfRM(rm)),
7037 nameXMMReg(gregOfRM(rm)) );
7038 delta += 1;
7039 } else {
7040 addr = disAMode ( &alen, sorb, delta, dis_buf );
7041 epart = loadLE(Ity_V128, mkexpr(addr));
7042 DIP("%s %s,%s\n", opname,
7043 dis_buf,
7044 nameXMMReg(gregOfRM(rm)) );
7045 delta += alen;
7046 }
7047 putXMMReg( gregOfRM(rm),
7048 eLeft ? binop(op, epart, gpart)
7049 : binop(op, gpart, epart) );
7050 return delta;
7051}
7052
7053
sewardjfd226452004-12-07 19:02:18 +00007054/* Helper for doing SSE FP comparisons. */
sewardj0bd7ce62004-12-05 02:47:40 +00007055
sewardj1e6ad742004-12-02 16:16:11 +00007056static void findSSECmpOp ( Bool* needNot, IROp* op,
7057 Int imm8, Bool all_lanes, Int sz )
7058{
7059 imm8 &= 7;
7060 *needNot = False;
7061 *op = Iop_INVALID;
7062 if (imm8 >= 4) {
7063 *needNot = True;
7064 imm8 -= 4;
7065 }
7066
7067 if (sz == 4 && all_lanes) {
7068 switch (imm8) {
7069 case 0: *op = Iop_CmpEQ32Fx4; return;
7070 case 1: *op = Iop_CmpLT32Fx4; return;
7071 case 2: *op = Iop_CmpLE32Fx4; return;
7072 case 3: *op = Iop_CmpUN32Fx4; return;
7073 default: break;
7074 }
7075 }
7076 if (sz == 4 && !all_lanes) {
7077 switch (imm8) {
7078 case 0: *op = Iop_CmpEQ32F0x4; return;
7079 case 1: *op = Iop_CmpLT32F0x4; return;
7080 case 2: *op = Iop_CmpLE32F0x4; return;
7081 case 3: *op = Iop_CmpUN32F0x4; return;
7082 default: break;
7083 }
7084 }
sewardjfd226452004-12-07 19:02:18 +00007085 if (sz == 8 && all_lanes) {
7086 switch (imm8) {
7087 case 0: *op = Iop_CmpEQ64Fx2; return;
7088 case 1: *op = Iop_CmpLT64Fx2; return;
7089 case 2: *op = Iop_CmpLE64Fx2; return;
7090 case 3: *op = Iop_CmpUN64Fx2; return;
7091 default: break;
7092 }
7093 }
7094 if (sz == 8 && !all_lanes) {
7095 switch (imm8) {
7096 case 0: *op = Iop_CmpEQ64F0x2; return;
7097 case 1: *op = Iop_CmpLT64F0x2; return;
7098 case 2: *op = Iop_CmpLE64F0x2; return;
7099 case 3: *op = Iop_CmpUN64F0x2; return;
7100 default: break;
7101 }
sewardj1e6ad742004-12-02 16:16:11 +00007102 }
7103 vpanic("findSSECmpOp(x86,guest)");
7104}
7105
sewardj33c69e52006-01-01 17:15:19 +00007106/* Handles SSE 32F/64F comparisons. */
sewardj129b3d92004-12-05 15:42:05 +00007107
sewardj52d04912005-07-03 00:52:48 +00007108static UInt dis_SSEcmp_E_to_G ( UChar sorb, Int delta,
sewardj1e6ad742004-12-02 16:16:11 +00007109 HChar* opname, Bool all_lanes, Int sz )
7110{
7111 HChar dis_buf[50];
7112 Int alen, imm8;
7113 IRTemp addr;
7114 Bool needNot = False;
7115 IROp op = Iop_INVALID;
7116 IRTemp plain = newTemp(Ity_V128);
7117 UChar rm = getIByte(delta);
7118 UShort mask = 0;
7119 vassert(sz == 4 || sz == 8);
7120 if (epartIsReg(rm)) {
7121 imm8 = getIByte(delta+1);
7122 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7123 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
7124 getXMMReg(eregOfRM(rm))) );
7125 delta += 2;
7126 DIP("%s $%d,%s,%s\n", opname,
7127 (Int)imm8,
7128 nameXMMReg(eregOfRM(rm)),
7129 nameXMMReg(gregOfRM(rm)) );
7130 } else {
7131 addr = disAMode ( &alen, sorb, delta, dis_buf );
7132 imm8 = getIByte(delta+alen);
7133 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
sewardj33c69e52006-01-01 17:15:19 +00007134 assign( plain,
7135 binop(
7136 op,
7137 getXMMReg(gregOfRM(rm)),
7138 all_lanes ? loadLE(Ity_V128, mkexpr(addr))
7139 : sz == 8 ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
7140 : /*sz==4*/ unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
7141 )
7142 );
sewardj1e6ad742004-12-02 16:16:11 +00007143 delta += alen+1;
7144 DIP("%s $%d,%s,%s\n", opname,
7145 (Int)imm8,
7146 dis_buf,
7147 nameXMMReg(gregOfRM(rm)) );
7148 }
7149
sewardj2e383862004-12-12 16:46:47 +00007150 if (needNot && all_lanes) {
7151 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00007152 unop(Iop_NotV128, mkexpr(plain)) );
sewardj2e383862004-12-12 16:46:47 +00007153 }
7154 else
7155 if (needNot && !all_lanes) {
sewardj9b45b482005-02-07 01:42:18 +00007156 mask = toUShort( sz==4 ? 0x000F : 0x00FF );
sewardj2e383862004-12-12 16:46:47 +00007157 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00007158 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
sewardj2e383862004-12-12 16:46:47 +00007159 }
7160 else {
7161 putXMMReg( gregOfRM(rm), mkexpr(plain) );
7162 }
sewardj1e6ad742004-12-02 16:16:11 +00007163
sewardj1e6ad742004-12-02 16:16:11 +00007164 return delta;
7165}
7166
sewardjb9fa69b2004-12-09 23:25:14 +00007167
7168/* Vector by scalar shift of G by the amount specified at the bottom
7169 of E. */
7170
sewardj52d04912005-07-03 00:52:48 +00007171static UInt dis_SSE_shiftG_byE ( UChar sorb, Int delta,
sewardjb9fa69b2004-12-09 23:25:14 +00007172 HChar* opname, IROp op )
7173{
7174 HChar dis_buf[50];
7175 Int alen, size;
7176 IRTemp addr;
7177 Bool shl, shr, sar;
7178 UChar rm = getIByte(delta);
7179 IRTemp g0 = newTemp(Ity_V128);
7180 IRTemp g1 = newTemp(Ity_V128);
7181 IRTemp amt = newTemp(Ity_I32);
7182 IRTemp amt8 = newTemp(Ity_I8);
7183 if (epartIsReg(rm)) {
7184 assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
7185 DIP("%s %s,%s\n", opname,
7186 nameXMMReg(eregOfRM(rm)),
7187 nameXMMReg(gregOfRM(rm)) );
7188 delta++;
7189 } else {
7190 addr = disAMode ( &alen, sorb, delta, dis_buf );
7191 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
7192 DIP("%s %s,%s\n", opname,
7193 dis_buf,
7194 nameXMMReg(gregOfRM(rm)) );
7195 delta += alen;
7196 }
7197 assign( g0, getXMMReg(gregOfRM(rm)) );
7198 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
7199
7200 shl = shr = sar = False;
7201 size = 0;
7202 switch (op) {
7203 case Iop_ShlN16x8: shl = True; size = 32; break;
7204 case Iop_ShlN32x4: shl = True; size = 32; break;
7205 case Iop_ShlN64x2: shl = True; size = 64; break;
7206 case Iop_SarN16x8: sar = True; size = 16; break;
7207 case Iop_SarN32x4: sar = True; size = 32; break;
7208 case Iop_ShrN16x8: shr = True; size = 16; break;
7209 case Iop_ShrN32x4: shr = True; size = 32; break;
7210 case Iop_ShrN64x2: shr = True; size = 64; break;
7211 default: vassert(0);
7212 }
7213
7214 if (shl || shr) {
7215 assign(
7216 g1,
7217 IRExpr_Mux0X(
7218 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
7219 mkV128(0x0000),
7220 binop(op, mkexpr(g0), mkexpr(amt8))
7221 )
7222 );
7223 } else
7224 if (sar) {
7225 assign(
7226 g1,
7227 IRExpr_Mux0X(
7228 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
7229 binop(op, mkexpr(g0), mkU8(size-1)),
7230 binop(op, mkexpr(g0), mkexpr(amt8))
7231 )
7232 );
7233 } else {
sewardjba89f4c2005-04-07 17:31:27 +00007234 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00007235 vassert(0);
7236 }
7237
7238 putXMMReg( gregOfRM(rm), mkexpr(g1) );
7239 return delta;
7240}
7241
7242
7243/* Vector by scalar shift of E by an immediate byte. */
7244
sewardj38a3f862005-01-13 15:06:51 +00007245static
sewardj52d04912005-07-03 00:52:48 +00007246UInt dis_SSE_shiftE_imm ( Int delta, HChar* opname, IROp op )
sewardjb9fa69b2004-12-09 23:25:14 +00007247{
7248 Bool shl, shr, sar;
7249 UChar rm = getIByte(delta);
sewardj38a3f862005-01-13 15:06:51 +00007250 IRTemp e0 = newTemp(Ity_V128);
7251 IRTemp e1 = newTemp(Ity_V128);
sewardjb9fa69b2004-12-09 23:25:14 +00007252 UChar amt, size;
7253 vassert(epartIsReg(rm));
7254 vassert(gregOfRM(rm) == 2
7255 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00007256 amt = getIByte(delta+1);
sewardjb9fa69b2004-12-09 23:25:14 +00007257 delta += 2;
7258 DIP("%s $%d,%s\n", opname,
7259 (Int)amt,
7260 nameXMMReg(eregOfRM(rm)) );
sewardj38a3f862005-01-13 15:06:51 +00007261 assign( e0, getXMMReg(eregOfRM(rm)) );
sewardjb9fa69b2004-12-09 23:25:14 +00007262
7263 shl = shr = sar = False;
7264 size = 0;
7265 switch (op) {
7266 case Iop_ShlN16x8: shl = True; size = 16; break;
7267 case Iop_ShlN32x4: shl = True; size = 32; break;
7268 case Iop_ShlN64x2: shl = True; size = 64; break;
7269 case Iop_SarN16x8: sar = True; size = 16; break;
7270 case Iop_SarN32x4: sar = True; size = 32; break;
7271 case Iop_ShrN16x8: shr = True; size = 16; break;
7272 case Iop_ShrN32x4: shr = True; size = 32; break;
7273 case Iop_ShrN64x2: shr = True; size = 64; break;
7274 default: vassert(0);
7275 }
7276
7277 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00007278 assign( e1, amt >= size
7279 ? mkV128(0x0000)
7280 : binop(op, mkexpr(e0), mkU8(amt))
7281 );
sewardjb9fa69b2004-12-09 23:25:14 +00007282 } else
7283 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00007284 assign( e1, amt >= size
7285 ? binop(op, mkexpr(e0), mkU8(size-1))
7286 : binop(op, mkexpr(e0), mkU8(amt))
7287 );
sewardjb9fa69b2004-12-09 23:25:14 +00007288 } else {
sewardjba89f4c2005-04-07 17:31:27 +00007289 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00007290 vassert(0);
7291 }
7292
sewardj38a3f862005-01-13 15:06:51 +00007293 putXMMReg( eregOfRM(rm), mkexpr(e1) );
sewardjb9fa69b2004-12-09 23:25:14 +00007294 return delta;
7295}
7296
7297
sewardjc1e7dfc2004-12-05 19:29:45 +00007298/* Get the current SSE rounding mode. */
sewardjc9a65702004-07-07 16:32:57 +00007299
sewardj4cb918d2004-12-03 19:43:31 +00007300static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
7301{
7302 return binop( Iop_And32,
7303 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
7304 mkU32(3) );
7305}
7306
sewardj636ad762004-12-07 11:16:04 +00007307static void put_sse_roundingmode ( IRExpr* sseround )
7308{
sewardjdd40fdf2006-12-24 02:20:24 +00007309 vassert(typeOfIRExpr(irsb->tyenv, sseround) == Ity_I32);
sewardj636ad762004-12-07 11:16:04 +00007310 stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
7311}
7312
sewardjc1e7dfc2004-12-05 19:29:45 +00007313/* Break a 128-bit value up into four 32-bit ints. */
7314
7315static void breakup128to32s ( IRTemp t128,
7316 /*OUTs*/
7317 IRTemp* t3, IRTemp* t2,
7318 IRTemp* t1, IRTemp* t0 )
7319{
7320 IRTemp hi64 = newTemp(Ity_I64);
7321 IRTemp lo64 = newTemp(Ity_I64);
sewardjf0c1c582005-02-07 23:47:38 +00007322 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
7323 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
sewardjc1e7dfc2004-12-05 19:29:45 +00007324
7325 vassert(t0 && *t0 == IRTemp_INVALID);
7326 vassert(t1 && *t1 == IRTemp_INVALID);
7327 vassert(t2 && *t2 == IRTemp_INVALID);
7328 vassert(t3 && *t3 == IRTemp_INVALID);
7329
7330 *t0 = newTemp(Ity_I32);
7331 *t1 = newTemp(Ity_I32);
7332 *t2 = newTemp(Ity_I32);
7333 *t3 = newTemp(Ity_I32);
7334 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
7335 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
7336 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
7337 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
7338}
7339
7340/* Construct a 128-bit value from four 32-bit ints. */
7341
7342static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
7343 IRTemp t1, IRTemp t0 )
7344{
7345 return
sewardjf0c1c582005-02-07 23:47:38 +00007346 binop( Iop_64HLtoV128,
sewardjc1e7dfc2004-12-05 19:29:45 +00007347 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
7348 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
7349 );
7350}
7351
sewardjb9fa69b2004-12-09 23:25:14 +00007352/* Break a 64-bit value up into four 16-bit ints. */
7353
7354static void breakup64to16s ( IRTemp t64,
7355 /*OUTs*/
7356 IRTemp* t3, IRTemp* t2,
7357 IRTemp* t1, IRTemp* t0 )
7358{
7359 IRTemp hi32 = newTemp(Ity_I32);
7360 IRTemp lo32 = newTemp(Ity_I32);
7361 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
7362 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
7363
7364 vassert(t0 && *t0 == IRTemp_INVALID);
7365 vassert(t1 && *t1 == IRTemp_INVALID);
7366 vassert(t2 && *t2 == IRTemp_INVALID);
7367 vassert(t3 && *t3 == IRTemp_INVALID);
7368
7369 *t0 = newTemp(Ity_I16);
7370 *t1 = newTemp(Ity_I16);
7371 *t2 = newTemp(Ity_I16);
7372 *t3 = newTemp(Ity_I16);
7373 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
7374 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
7375 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
7376 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
7377}
7378
7379/* Construct a 64-bit value from four 16-bit ints. */
7380
7381static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
7382 IRTemp t1, IRTemp t0 )
7383{
7384 return
7385 binop( Iop_32HLto64,
7386 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7387 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7388 );
7389}
7390
sewardj0e9a0f52008-01-04 01:22:41 +00007391/* Generate IR to set the guest %EFLAGS from the pushfl-format image
7392 in the given 32-bit temporary. The flags that are set are: O S Z A
7393 C P D ID AC.
7394
7395 In all cases, code to set AC is generated. However, VEX actually
7396 ignores the AC value and so can optionally emit an emulation
7397 warning when it is enabled. In this routine, an emulation warning
7398 is only emitted if emit_AC_emwarn is True, in which case
7399 next_insn_EIP must be correct (this allows for correct code
7400 generation for popfl/popfw). If emit_AC_emwarn is False,
7401 next_insn_EIP is unimportant (this allows for easy if kludgey code
7402 generation for IRET.) */
7403
7404static
7405void set_EFLAGS_from_value ( IRTemp t1,
7406 Bool emit_AC_emwarn,
7407 Addr32 next_insn_EIP )
7408{
7409 vassert(typeOfIRTemp(irsb->tyenv,t1) == Ity_I32);
7410
7411 /* t1 is the flag word. Mask out everything except OSZACP and set
7412 the flags thunk to X86G_CC_OP_COPY. */
7413 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7414 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7415 stmt( IRStmt_Put( OFFB_CC_DEP1,
7416 binop(Iop_And32,
7417 mkexpr(t1),
7418 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
7419 | X86G_CC_MASK_A | X86G_CC_MASK_Z
7420 | X86G_CC_MASK_S| X86G_CC_MASK_O )
7421 )
7422 )
7423 );
7424 /* Set NDEP even though it isn't used. This makes redundant-PUT
7425 elimination of previous stores to this field work better. */
7426 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
7427
7428 /* Also need to set the D flag, which is held in bit 10 of t1.
7429 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
7430 stmt( IRStmt_Put(
7431 OFFB_DFLAG,
7432 IRExpr_Mux0X(
7433 unop(Iop_32to8,
7434 binop(Iop_And32,
7435 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
7436 mkU32(1))),
7437 mkU32(1),
7438 mkU32(0xFFFFFFFF)))
7439 );
7440
7441 /* Set the ID flag */
7442 stmt( IRStmt_Put(
7443 OFFB_IDFLAG,
7444 IRExpr_Mux0X(
7445 unop(Iop_32to8,
7446 binop(Iop_And32,
7447 binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
7448 mkU32(1))),
7449 mkU32(0),
7450 mkU32(1)))
7451 );
7452
7453 /* And set the AC flag. If setting it 1 to, possibly emit an
7454 emulation warning. */
7455 stmt( IRStmt_Put(
7456 OFFB_ACFLAG,
7457 IRExpr_Mux0X(
7458 unop(Iop_32to8,
7459 binop(Iop_And32,
7460 binop(Iop_Shr32, mkexpr(t1), mkU8(18)),
7461 mkU32(1))),
7462 mkU32(0),
7463 mkU32(1)))
7464 );
7465
7466 if (emit_AC_emwarn) {
7467 put_emwarn( mkU32(EmWarn_X86_acFlag) );
7468 stmt(
7469 IRStmt_Exit(
7470 binop( Iop_CmpNE32,
7471 binop(Iop_And32, mkexpr(t1), mkU32(1<<18)),
7472 mkU32(0) ),
7473 Ijk_EmWarn,
7474 IRConst_U32( next_insn_EIP )
7475 )
7476 );
7477 }
7478}
7479
sewardj4cb918d2004-12-03 19:43:31 +00007480
sewardj150c9cd2008-02-09 01:16:02 +00007481/* Helper for the SSSE3 (not SSE3) PMULHRSW insns. Given two 64-bit
7482 values (aa,bb), computes, for each of the 4 16-bit lanes:
7483
7484 (((aa_lane *s32 bb_lane) >>u 14) + 1) >>u 1
7485*/
7486static IRExpr* dis_PMULHRSW_helper ( IRExpr* aax, IRExpr* bbx )
7487{
7488 IRTemp aa = newTemp(Ity_I64);
7489 IRTemp bb = newTemp(Ity_I64);
7490 IRTemp aahi32s = newTemp(Ity_I64);
7491 IRTemp aalo32s = newTemp(Ity_I64);
7492 IRTemp bbhi32s = newTemp(Ity_I64);
7493 IRTemp bblo32s = newTemp(Ity_I64);
7494 IRTemp rHi = newTemp(Ity_I64);
7495 IRTemp rLo = newTemp(Ity_I64);
7496 IRTemp one32x2 = newTemp(Ity_I64);
7497 assign(aa, aax);
7498 assign(bb, bbx);
7499 assign( aahi32s,
7500 binop(Iop_SarN32x2,
7501 binop(Iop_InterleaveHI16x4, mkexpr(aa), mkexpr(aa)),
7502 mkU8(16) ));
7503 assign( aalo32s,
7504 binop(Iop_SarN32x2,
7505 binop(Iop_InterleaveLO16x4, mkexpr(aa), mkexpr(aa)),
7506 mkU8(16) ));
7507 assign( bbhi32s,
7508 binop(Iop_SarN32x2,
7509 binop(Iop_InterleaveHI16x4, mkexpr(bb), mkexpr(bb)),
7510 mkU8(16) ));
7511 assign( bblo32s,
7512 binop(Iop_SarN32x2,
7513 binop(Iop_InterleaveLO16x4, mkexpr(bb), mkexpr(bb)),
7514 mkU8(16) ));
7515 assign(one32x2, mkU64( (1ULL << 32) + 1 ));
7516 assign(
7517 rHi,
7518 binop(
7519 Iop_ShrN32x2,
7520 binop(
7521 Iop_Add32x2,
7522 binop(
7523 Iop_ShrN32x2,
7524 binop(Iop_Mul32x2, mkexpr(aahi32s), mkexpr(bbhi32s)),
7525 mkU8(14)
7526 ),
7527 mkexpr(one32x2)
7528 ),
7529 mkU8(1)
7530 )
7531 );
7532 assign(
7533 rLo,
7534 binop(
7535 Iop_ShrN32x2,
7536 binop(
7537 Iop_Add32x2,
7538 binop(
7539 Iop_ShrN32x2,
7540 binop(Iop_Mul32x2, mkexpr(aalo32s), mkexpr(bblo32s)),
7541 mkU8(14)
7542 ),
7543 mkexpr(one32x2)
7544 ),
7545 mkU8(1)
7546 )
7547 );
7548 return
7549 binop(Iop_CatEvenLanes16x4, mkexpr(rHi), mkexpr(rLo));
7550}
7551
7552/* Helper for the SSSE3 (not SSE3) PSIGN{B,W,D} insns. Given two 64-bit
7553 values (aa,bb), computes, for each lane:
7554
7555 if aa_lane < 0 then - bb_lane
7556 else if aa_lane > 0 then bb_lane
7557 else 0
7558*/
7559static IRExpr* dis_PSIGN_helper ( IRExpr* aax, IRExpr* bbx, Int laneszB )
7560{
7561 IRTemp aa = newTemp(Ity_I64);
7562 IRTemp bb = newTemp(Ity_I64);
7563 IRTemp zero = newTemp(Ity_I64);
7564 IRTemp bbNeg = newTemp(Ity_I64);
7565 IRTemp negMask = newTemp(Ity_I64);
7566 IRTemp posMask = newTemp(Ity_I64);
7567 IROp opSub = Iop_INVALID;
7568 IROp opCmpGTS = Iop_INVALID;
7569
7570 switch (laneszB) {
7571 case 1: opSub = Iop_Sub8x8; opCmpGTS = Iop_CmpGT8Sx8; break;
7572 case 2: opSub = Iop_Sub16x4; opCmpGTS = Iop_CmpGT16Sx4; break;
7573 case 4: opSub = Iop_Sub32x2; opCmpGTS = Iop_CmpGT32Sx2; break;
7574 default: vassert(0);
7575 }
7576
7577 assign( aa, aax );
7578 assign( bb, bbx );
7579 assign( zero, mkU64(0) );
7580 assign( bbNeg, binop(opSub, mkexpr(zero), mkexpr(bb)) );
7581 assign( negMask, binop(opCmpGTS, mkexpr(zero), mkexpr(aa)) );
7582 assign( posMask, binop(opCmpGTS, mkexpr(aa), mkexpr(zero)) );
7583
7584 return
7585 binop(Iop_Or64,
7586 binop(Iop_And64, mkexpr(bb), mkexpr(posMask)),
7587 binop(Iop_And64, mkexpr(bbNeg), mkexpr(negMask)) );
7588
7589}
7590
7591/* Helper for the SSSE3 (not SSE3) PABS{B,W,D} insns. Given a 64-bit
7592 value aa, computes, for each lane
7593
7594 if aa < 0 then -aa else aa
7595
7596 Note that the result is interpreted as unsigned, so that the
7597 absolute value of the most negative signed input can be
7598 represented.
7599*/
7600static IRExpr* dis_PABS_helper ( IRExpr* aax, Int laneszB )
7601{
7602 IRTemp aa = newTemp(Ity_I64);
7603 IRTemp zero = newTemp(Ity_I64);
7604 IRTemp aaNeg = newTemp(Ity_I64);
7605 IRTemp negMask = newTemp(Ity_I64);
7606 IRTemp posMask = newTemp(Ity_I64);
7607 IROp opSub = Iop_INVALID;
7608 IROp opSarN = Iop_INVALID;
7609
7610 switch (laneszB) {
7611 case 1: opSub = Iop_Sub8x8; opSarN = Iop_SarN8x8; break;
7612 case 2: opSub = Iop_Sub16x4; opSarN = Iop_SarN16x4; break;
7613 case 4: opSub = Iop_Sub32x2; opSarN = Iop_SarN32x2; break;
7614 default: vassert(0);
7615 }
7616
7617 assign( aa, aax );
7618 assign( negMask, binop(opSarN, mkexpr(aa), mkU8(8*laneszB-1)) );
7619 assign( posMask, unop(Iop_Not64, mkexpr(negMask)) );
7620 assign( zero, mkU64(0) );
7621 assign( aaNeg, binop(opSub, mkexpr(zero), mkexpr(aa)) );
7622 return
7623 binop(Iop_Or64,
7624 binop(Iop_And64, mkexpr(aa), mkexpr(posMask)),
7625 binop(Iop_And64, mkexpr(aaNeg), mkexpr(negMask)) );
7626}
7627
7628static IRExpr* dis_PALIGNR_XMM_helper ( IRTemp hi64,
7629 IRTemp lo64, Int byteShift )
7630{
7631 vassert(byteShift >= 1 && byteShift <= 7);
7632 return
7633 binop(Iop_Or64,
7634 binop(Iop_Shl64, mkexpr(hi64), mkU8(8*(8-byteShift))),
7635 binop(Iop_Shr64, mkexpr(lo64), mkU8(8*byteShift))
7636 );
7637}
7638
7639/* Generate a SIGSEGV followed by a restart of the current instruction
7640 if effective_addr is not 16-aligned. This is required behaviour
7641 for some SSE3 instructions and all 128-bit SSSE3 instructions.
7642 This assumes that guest_RIP_curr_instr is set correctly! */
7643static void gen_SEGV_if_not_16_aligned ( IRTemp effective_addr )
7644{
7645 stmt(
7646 IRStmt_Exit(
7647 binop(Iop_CmpNE32,
7648 binop(Iop_And32,mkexpr(effective_addr),mkU32(0xF)),
7649 mkU32(0)),
7650 Ijk_SigSEGV,
7651 IRConst_U32(guest_EIP_curr_instr)
7652 )
7653 );
7654}
7655
7656
sewardjc4356f02007-11-09 21:15:04 +00007657/* Helper for deciding whether a given insn (starting at the opcode
7658 byte) may validly be used with a LOCK prefix. The following insns
7659 may be used with LOCK when their destination operand is in memory.
sewardje9d8a262009-07-01 08:06:34 +00007660 AFAICS this is exactly the same for both 32-bit and 64-bit mode.
sewardjc4356f02007-11-09 21:15:04 +00007661
sewardje9d8a262009-07-01 08:06:34 +00007662 ADD 80 /0, 81 /0, 82 /0, 83 /0, 00, 01
7663 OR 80 /1, 81 /1, 82 /x, 83 /1, 08, 09
7664 ADC 80 /2, 81 /2, 82 /2, 83 /2, 10, 11
7665 SBB 81 /3, 81 /3, 82 /x, 83 /3, 18, 19
7666 AND 80 /4, 81 /4, 82 /x, 83 /4, 20, 21
7667 SUB 80 /5, 81 /5, 82 /x, 83 /5, 28, 29
7668 XOR 80 /6, 81 /6, 82 /x, 83 /6, 30, 31
sewardjc4356f02007-11-09 21:15:04 +00007669
7670 DEC FE /1, FF /1
7671 INC FE /0, FF /0
7672
7673 NEG F6 /3, F7 /3
7674 NOT F6 /2, F7 /2
7675
sewardje9d8a262009-07-01 08:06:34 +00007676 XCHG 86, 87
sewardjc4356f02007-11-09 21:15:04 +00007677
7678 BTC 0F BB, 0F BA /7
7679 BTR 0F B3, 0F BA /6
7680 BTS 0F AB, 0F BA /5
7681
7682 CMPXCHG 0F B0, 0F B1
7683 CMPXCHG8B 0F C7 /1
7684
7685 XADD 0F C0, 0F C1
sewardje9d8a262009-07-01 08:06:34 +00007686
7687 ------------------------------
7688
7689 80 /0 = addb $imm8, rm8
7690 81 /0 = addl $imm32, rm32 and addw $imm16, rm16
7691 82 /0 = addb $imm8, rm8
7692 83 /0 = addl $simm8, rm32 and addw $simm8, rm16
7693
7694 00 = addb r8, rm8
7695 01 = addl r32, rm32 and addw r16, rm16
7696
7697 Same for ADD OR ADC SBB AND SUB XOR
7698
7699 FE /1 = dec rm8
7700 FF /1 = dec rm32 and dec rm16
7701
7702 FE /0 = inc rm8
7703 FF /0 = inc rm32 and inc rm16
7704
7705 F6 /3 = neg rm8
7706 F7 /3 = neg rm32 and neg rm16
7707
7708 F6 /2 = not rm8
7709 F7 /2 = not rm32 and not rm16
7710
7711 0F BB = btcw r16, rm16 and btcl r32, rm32
7712 OF BA /7 = btcw $imm8, rm16 and btcw $imm8, rm32
7713
7714 Same for BTS, BTR
sewardjc4356f02007-11-09 21:15:04 +00007715*/
7716static Bool can_be_used_with_LOCK_prefix ( UChar* opc )
7717{
7718 switch (opc[0]) {
sewardje9d8a262009-07-01 08:06:34 +00007719 case 0x00: case 0x01: case 0x08: case 0x09:
7720 case 0x10: case 0x11: case 0x18: case 0x19:
7721 case 0x20: case 0x21: case 0x28: case 0x29:
7722 case 0x30: case 0x31:
7723 if (!epartIsReg(opc[1]))
7724 return True;
7725 break;
sewardjc4356f02007-11-09 21:15:04 +00007726
sewardje9d8a262009-07-01 08:06:34 +00007727 case 0x80: case 0x81: case 0x82: case 0x83:
7728 if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 6
7729 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00007730 return True;
7731 break;
7732
7733 case 0xFE: case 0xFF:
sewardje9d8a262009-07-01 08:06:34 +00007734 if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 1
7735 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00007736 return True;
7737 break;
7738
7739 case 0xF6: case 0xF7:
sewardje9d8a262009-07-01 08:06:34 +00007740 if (gregOfRM(opc[1]) >= 2 && gregOfRM(opc[1]) <= 3
7741 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00007742 return True;
7743 break;
7744
7745 case 0x86: case 0x87:
sewardje9d8a262009-07-01 08:06:34 +00007746 if (!epartIsReg(opc[1]))
7747 return True;
7748 break;
sewardjc4356f02007-11-09 21:15:04 +00007749
7750 case 0x0F: {
7751 switch (opc[1]) {
7752 case 0xBB: case 0xB3: case 0xAB:
sewardje9d8a262009-07-01 08:06:34 +00007753 if (!epartIsReg(opc[2]))
7754 return True;
7755 break;
sewardjc4356f02007-11-09 21:15:04 +00007756 case 0xBA:
sewardje9d8a262009-07-01 08:06:34 +00007757 if (gregOfRM(opc[2]) >= 5 && gregOfRM(opc[2]) <= 7
7758 && !epartIsReg(opc[2]))
sewardjc4356f02007-11-09 21:15:04 +00007759 return True;
7760 break;
7761 case 0xB0: case 0xB1:
sewardje9d8a262009-07-01 08:06:34 +00007762 if (!epartIsReg(opc[2]))
7763 return True;
7764 break;
sewardjc4356f02007-11-09 21:15:04 +00007765 case 0xC7:
sewardje9d8a262009-07-01 08:06:34 +00007766 if (gregOfRM(opc[2]) == 1 && !epartIsReg(opc[2]) )
sewardjc4356f02007-11-09 21:15:04 +00007767 return True;
7768 break;
7769 case 0xC0: case 0xC1:
sewardje9d8a262009-07-01 08:06:34 +00007770 if (!epartIsReg(opc[2]))
7771 return True;
7772 break;
sewardjc4356f02007-11-09 21:15:04 +00007773 default:
7774 break;
7775 } /* switch (opc[1]) */
7776 break;
7777 }
7778
7779 default:
7780 break;
7781 } /* switch (opc[0]) */
7782
7783 return False;
7784}
7785
7786
sewardjc9a65702004-07-07 16:32:57 +00007787/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +00007788/*--- Disassemble a single instruction ---*/
sewardjc9a65702004-07-07 16:32:57 +00007789/*------------------------------------------------------------*/
7790
sewardje9d8a262009-07-01 08:06:34 +00007791/* Disassemble a single instruction into IR. The instruction is
7792 located in host memory at &guest_code[delta]. *expect_CAS is set
7793 to True if the resulting IR is expected to contain an IRCAS
7794 statement, and False if it's not expected to. This makes it
7795 possible for the caller of disInstr_X86_WRK to check that
7796 LOCK-prefixed instructions are at least plausibly translated, in
7797 that it becomes possible to check that a (validly) LOCK-prefixed
7798 instruction generates a translation containing an IRCAS, and
7799 instructions without LOCK prefixes don't generate translations
7800 containing an IRCAS.
7801*/
sewardj9e6491a2005-07-02 19:24:10 +00007802static
sewardje9d8a262009-07-01 08:06:34 +00007803DisResult disInstr_X86_WRK (
7804 /*OUT*/Bool* expect_CAS,
sewardj9e6491a2005-07-02 19:24:10 +00007805 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +00007806 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +00007807 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +00007808 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +00007809 Long delta64,
7810 VexArchInfo* archinfo
7811 )
sewardjc9a65702004-07-07 16:32:57 +00007812{
sewardjce70a5c2004-10-18 14:09:54 +00007813 IRType ty;
sewardjb5452082004-12-04 20:33:02 +00007814 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjce70a5c2004-10-18 14:09:54 +00007815 Int alen;
sewardjc4356f02007-11-09 21:15:04 +00007816 UChar opc, modrm, abyte, pre;
sewardjce70a5c2004-10-18 14:09:54 +00007817 UInt d32;
sewardjc9a43662004-11-30 18:51:59 +00007818 HChar dis_buf[50];
sewardjc4356f02007-11-09 21:15:04 +00007819 Int am_sz, d_sz, n_prefixes;
sewardj9e6491a2005-07-02 19:24:10 +00007820 DisResult dres;
sewardjc9a43662004-11-30 18:51:59 +00007821 UChar* insn; /* used in SSE decoders */
sewardjce70a5c2004-10-18 14:09:54 +00007822
sewardj9e6491a2005-07-02 19:24:10 +00007823 /* The running delta */
7824 Int delta = (Int)delta64;
7825
sewardjc9a65702004-07-07 16:32:57 +00007826 /* Holds eip at the start of the insn, so that we can print
7827 consistent error messages for unimplemented insns. */
sewardj9e6491a2005-07-02 19:24:10 +00007828 Int delta_start = delta;
sewardjc9a65702004-07-07 16:32:57 +00007829
7830 /* sz denotes the nominal data-op size of the insn; we change it to
7831 2 if an 0x66 prefix is seen */
7832 Int sz = 4;
7833
7834 /* sorb holds the segment-override-prefix byte, if any. Zero if no
7835 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
7836 indicating the prefix. */
7837 UChar sorb = 0;
7838
sewardjc4356f02007-11-09 21:15:04 +00007839 /* Gets set to True if a LOCK prefix is seen. */
7840 Bool pfx_lock = False;
7841
sewardj9e6491a2005-07-02 19:24:10 +00007842 /* Set result defaults. */
7843 dres.whatNext = Dis_Continue;
7844 dres.len = 0;
7845 dres.continueAt = 0;
sewardjce70a5c2004-10-18 14:09:54 +00007846
sewardje9d8a262009-07-01 08:06:34 +00007847 *expect_CAS = False;
7848
sewardjb5452082004-12-04 20:33:02 +00007849 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjc9a65702004-07-07 16:32:57 +00007850
sewardje9d8a262009-07-01 08:06:34 +00007851 vassert(guest_EIP_bbstart + delta == guest_EIP_curr_instr);
sewardj9e6491a2005-07-02 19:24:10 +00007852 DIP("\t0x%x: ", guest_EIP_bbstart+delta);
7853
7854 /* We may be asked to update the guest EIP before going further. */
7855 if (put_IP)
7856 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr)) );
sewardjc9a65702004-07-07 16:32:57 +00007857
sewardjce02aa72006-01-12 12:27:58 +00007858 /* Spot "Special" instructions (see comment at top of file). */
sewardj750f4072004-07-26 22:39:11 +00007859 {
7860 UChar* code = (UChar*)(guest_code + delta);
sewardjce02aa72006-01-12 12:27:58 +00007861 /* Spot the 12-byte preamble:
7862 C1C703 roll $3, %edi
7863 C1C70D roll $13, %edi
7864 C1C71D roll $29, %edi
7865 C1C713 roll $19, %edi
sewardj750f4072004-07-26 22:39:11 +00007866 */
sewardjce02aa72006-01-12 12:27:58 +00007867 if (code[ 0] == 0xC1 && code[ 1] == 0xC7 && code[ 2] == 0x03 &&
7868 code[ 3] == 0xC1 && code[ 4] == 0xC7 && code[ 5] == 0x0D &&
7869 code[ 6] == 0xC1 && code[ 7] == 0xC7 && code[ 8] == 0x1D &&
7870 code[ 9] == 0xC1 && code[10] == 0xC7 && code[11] == 0x13) {
7871 /* Got a "Special" instruction preamble. Which one is it? */
7872 if (code[12] == 0x87 && code[13] == 0xDB /* xchgl %ebx,%ebx */) {
7873 /* %EDX = client_request ( %EAX ) */
7874 DIP("%%edx = client_request ( %%eax )\n");
7875 delta += 14;
7876 jmp_lit(Ijk_ClientReq, guest_EIP_bbstart+delta);
7877 dres.whatNext = Dis_StopHere;
7878 goto decode_success;
7879 }
7880 else
7881 if (code[12] == 0x87 && code[13] == 0xC9 /* xchgl %ecx,%ecx */) {
7882 /* %EAX = guest_NRADDR */
7883 DIP("%%eax = guest_NRADDR\n");
7884 delta += 14;
7885 putIReg(4, R_EAX, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
7886 goto decode_success;
7887 }
7888 else
7889 if (code[12] == 0x87 && code[13] == 0xD2 /* xchgl %edx,%edx */) {
7890 /* call-noredir *%EAX */
7891 DIP("call-noredir *%%eax\n");
7892 delta += 14;
7893 t1 = newTemp(Ity_I32);
7894 assign(t1, getIReg(4,R_EAX));
7895 t2 = newTemp(Ity_I32);
7896 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
7897 putIReg(4, R_ESP, mkexpr(t2));
7898 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta));
7899 jmp_treg(Ijk_NoRedir,t1);
7900 dres.whatNext = Dis_StopHere;
7901 goto decode_success;
7902 }
7903 /* We don't know what it is. */
7904 goto decode_failure;
7905 /*NOTREACHED*/
sewardj750f4072004-07-26 22:39:11 +00007906 }
7907 }
sewardjc9a65702004-07-07 16:32:57 +00007908
sewardjc4356f02007-11-09 21:15:04 +00007909 /* Handle a couple of weird-ass NOPs that have been observed in the
7910 wild. */
7911 {
sewardjbb3f52d2005-01-07 14:14:50 +00007912 UChar* code = (UChar*)(guest_code + delta);
sewardjc4356f02007-11-09 21:15:04 +00007913 /* Sun's JVM 1.5.0 uses the following as a NOP:
7914 26 2E 64 65 90 %es:%cs:%fs:%gs:nop */
7915 if (code[0] == 0x26 && code[1] == 0x2E && code[2] == 0x64
7916 && code[3] == 0x65 && code[4] == 0x90) {
7917 DIP("%%es:%%cs:%%fs:%%gs:nop\n");
7918 delta += 5;
7919 goto decode_success;
sewardjbb3f52d2005-01-07 14:14:50 +00007920 }
sewardjdeceef82010-05-03 21:58:22 +00007921 /* Don't barf on recent binutils padding,
7922 all variants of which are: nopw %cs:0x0(%eax,%eax,1)
7923 66 2e 0f 1f 84 00 00 00 00 00
7924 66 66 2e 0f 1f 84 00 00 00 00 00
7925 66 66 66 2e 0f 1f 84 00 00 00 00 00
7926 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
7927 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
7928 66 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
7929 */
7930 if (code[0] == 0x66) {
7931 Int data16_cnt;
7932 for (data16_cnt = 1; data16_cnt < 6; data16_cnt++)
7933 if (code[data16_cnt] != 0x66)
7934 break;
7935 if (code[data16_cnt] == 0x2E && code[data16_cnt + 1] == 0x0F
7936 && code[data16_cnt + 2] == 0x1F && code[data16_cnt + 3] == 0x84
7937 && code[data16_cnt + 4] == 0x00 && code[data16_cnt + 5] == 0x00
7938 && code[data16_cnt + 6] == 0x00 && code[data16_cnt + 7] == 0x00
7939 && code[data16_cnt + 8] == 0x00 ) {
7940 DIP("nopw %%cs:0x0(%%eax,%%eax,1)\n");
7941 delta += 9 + data16_cnt;
7942 goto decode_success;
7943 }
sewardjce4a2822005-01-07 13:25:28 +00007944 }
sewardjc4356f02007-11-09 21:15:04 +00007945 }
sewardjbb3f52d2005-01-07 14:14:50 +00007946
sewardjc4356f02007-11-09 21:15:04 +00007947 /* Normal instruction handling starts here. */
sewardjc9a65702004-07-07 16:32:57 +00007948
sewardjc4356f02007-11-09 21:15:04 +00007949 /* Deal with some but not all prefixes:
7950 66(oso)
7951 F0(lock)
7952 2E(cs:) 3E(ds:) 26(es:) 64(fs:) 65(gs:) 36(ss:)
7953 Not dealt with (left in place):
7954 F2 F3
7955 */
7956 n_prefixes = 0;
7957 while (True) {
7958 if (n_prefixes > 7) goto decode_failure;
7959 pre = getUChar(delta);
7960 switch (pre) {
7961 case 0x66:
7962 sz = 2;
7963 break;
7964 case 0xF0:
7965 pfx_lock = True;
sewardje9d8a262009-07-01 08:06:34 +00007966 *expect_CAS = True;
sewardjc4356f02007-11-09 21:15:04 +00007967 break;
7968 case 0x3E: /* %DS: */
7969 case 0x26: /* %ES: */
7970 case 0x64: /* %FS: */
7971 case 0x65: /* %GS: */
7972 if (sorb != 0)
7973 goto decode_failure; /* only one seg override allowed */
7974 sorb = pre;
7975 break;
7976 case 0x2E: { /* %CS: */
7977 /* 2E prefix on a conditional branch instruction is a
7978 branch-prediction hint, which can safely be ignored. */
sewardjc9a65702004-07-07 16:32:57 +00007979 UChar op1 = getIByte(delta+1);
7980 UChar op2 = getIByte(delta+2);
7981 if ((op1 >= 0x70 && op1 <= 0x7F)
7982 || (op1 == 0xE3)
7983 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
sewardj4dfb1992005-03-13 18:56:28 +00007984 if (0) vex_printf("vex x86->IR: ignoring branch hint\n");
sewardjc4356f02007-11-09 21:15:04 +00007985 } else {
7986 /* All other CS override cases are not handled */
7987 goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +00007988 }
sewardjc4356f02007-11-09 21:15:04 +00007989 break;
sewardjc9a65702004-07-07 16:32:57 +00007990 }
sewardjc4356f02007-11-09 21:15:04 +00007991 case 0x36: /* %SS: */
7992 /* SS override cases are not handled */
7993 goto decode_failure;
7994 default:
7995 goto not_a_prefix;
7996 }
7997 n_prefixes++;
7998 delta++;
sewardjc9a65702004-07-07 16:32:57 +00007999 }
8000
sewardjc4356f02007-11-09 21:15:04 +00008001 not_a_prefix:
8002
8003 /* Now we should be looking at the primary opcode byte or the
8004 leading F2 or F3. Check that any LOCK prefix is actually
8005 allowed. */
8006
sewardjc4356f02007-11-09 21:15:04 +00008007 if (pfx_lock) {
8008 if (can_be_used_with_LOCK_prefix( (UChar*)&guest_code[delta] )) {
sewardjc4356f02007-11-09 21:15:04 +00008009 DIP("lock ");
8010 } else {
sewardje9d8a262009-07-01 08:06:34 +00008011 *expect_CAS = False;
sewardjc4356f02007-11-09 21:15:04 +00008012 goto decode_failure;
8013 }
8014 }
8015
8016
sewardjc9a43662004-11-30 18:51:59 +00008017 /* ---------------------------------------------------- */
8018 /* --- The SSE decoder. --- */
8019 /* ---------------------------------------------------- */
8020
sewardj4cb918d2004-12-03 19:43:31 +00008021 /* What did I do to deserve SSE ? Perhaps I was really bad in a
8022 previous life? */
8023
sewardj9df271d2004-12-31 22:37:42 +00008024 /* Note, this doesn't handle SSE2 or SSE3. That is handled in a
8025 later section, further on. */
8026
sewardja0e83b02005-01-06 12:36:38 +00008027 insn = (UChar*)&guest_code[delta];
8028
8029 /* Treat fxsave specially. It should be doable even on an SSE0
8030 (Pentium-II class) CPU. Hence be prepared to handle it on
8031 any subarchitecture variant.
8032 */
8033
8034 /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
8035 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8036 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj9a036bf2005-03-14 18:19:08 +00008037 IRDirty* d;
sewardja0e83b02005-01-06 12:36:38 +00008038 modrm = getIByte(delta+2);
8039 vassert(sz == 4);
8040 vassert(!epartIsReg(modrm));
8041
8042 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8043 delta += 2+alen;
8044
sewardj33dd31b2005-01-08 18:17:32 +00008045 DIP("fxsave %s\n", dis_buf);
sewardja0e83b02005-01-06 12:36:38 +00008046
8047 /* Uses dirty helper:
8048 void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
sewardj9a036bf2005-03-14 18:19:08 +00008049 d = unsafeIRDirty_0_N (
8050 0/*regparms*/,
8051 "x86g_dirtyhelper_FXSAVE",
8052 &x86g_dirtyhelper_FXSAVE,
8053 mkIRExprVec_1( mkexpr(addr) )
8054 );
sewardja0e83b02005-01-06 12:36:38 +00008055 d->needsBBP = True;
8056
8057 /* declare we're writing memory */
8058 d->mFx = Ifx_Write;
8059 d->mAddr = mkexpr(addr);
8060 d->mSize = 512;
8061
8062 /* declare we're reading guest state */
8063 d->nFxState = 7;
8064
8065 d->fxState[0].fx = Ifx_Read;
8066 d->fxState[0].offset = OFFB_FTOP;
8067 d->fxState[0].size = sizeof(UInt);
8068
8069 d->fxState[1].fx = Ifx_Read;
8070 d->fxState[1].offset = OFFB_FPREGS;
8071 d->fxState[1].size = 8 * sizeof(ULong);
8072
8073 d->fxState[2].fx = Ifx_Read;
8074 d->fxState[2].offset = OFFB_FPTAGS;
8075 d->fxState[2].size = 8 * sizeof(UChar);
8076
8077 d->fxState[3].fx = Ifx_Read;
8078 d->fxState[3].offset = OFFB_FPROUND;
8079 d->fxState[3].size = sizeof(UInt);
8080
8081 d->fxState[4].fx = Ifx_Read;
8082 d->fxState[4].offset = OFFB_FC3210;
8083 d->fxState[4].size = sizeof(UInt);
8084
8085 d->fxState[5].fx = Ifx_Read;
8086 d->fxState[5].offset = OFFB_XMM0;
8087 d->fxState[5].size = 8 * sizeof(U128);
8088
8089 d->fxState[6].fx = Ifx_Read;
8090 d->fxState[6].offset = OFFB_SSEROUND;
8091 d->fxState[6].size = sizeof(UInt);
8092
8093 /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8094 images are packed back-to-back. If not, the value of
8095 d->fxState[5].size is wrong. */
8096 vassert(16 == sizeof(U128));
8097 vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8098
8099 stmt( IRStmt_Dirty(d) );
8100
8101 goto decode_success;
8102 }
8103
sewardj3800e2d2008-05-09 13:24:43 +00008104 /* 0F AE /1 = FXRSTOR m512 -- read x87 and SSE state from memory */
8105 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8106 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 1) {
8107 IRDirty* d;
8108 modrm = getIByte(delta+2);
8109 vassert(sz == 4);
8110 vassert(!epartIsReg(modrm));
8111
8112 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8113 delta += 2+alen;
8114
8115 DIP("fxrstor %s\n", dis_buf);
8116
8117 /* Uses dirty helper:
8118 void x86g_do_FXRSTOR ( VexGuestX86State*, UInt ) */
8119 d = unsafeIRDirty_0_N (
8120 0/*regparms*/,
8121 "x86g_dirtyhelper_FXRSTOR",
8122 &x86g_dirtyhelper_FXRSTOR,
8123 mkIRExprVec_1( mkexpr(addr) )
8124 );
8125 d->needsBBP = True;
8126
8127 /* declare we're reading memory */
8128 d->mFx = Ifx_Read;
8129 d->mAddr = mkexpr(addr);
8130 d->mSize = 512;
8131
8132 /* declare we're writing guest state */
8133 d->nFxState = 7;
8134
8135 d->fxState[0].fx = Ifx_Write;
8136 d->fxState[0].offset = OFFB_FTOP;
8137 d->fxState[0].size = sizeof(UInt);
8138
8139 d->fxState[1].fx = Ifx_Write;
8140 d->fxState[1].offset = OFFB_FPREGS;
8141 d->fxState[1].size = 8 * sizeof(ULong);
8142
8143 d->fxState[2].fx = Ifx_Write;
8144 d->fxState[2].offset = OFFB_FPTAGS;
8145 d->fxState[2].size = 8 * sizeof(UChar);
8146
8147 d->fxState[3].fx = Ifx_Write;
8148 d->fxState[3].offset = OFFB_FPROUND;
8149 d->fxState[3].size = sizeof(UInt);
8150
8151 d->fxState[4].fx = Ifx_Write;
8152 d->fxState[4].offset = OFFB_FC3210;
8153 d->fxState[4].size = sizeof(UInt);
8154
8155 d->fxState[5].fx = Ifx_Write;
8156 d->fxState[5].offset = OFFB_XMM0;
8157 d->fxState[5].size = 8 * sizeof(U128);
8158
8159 d->fxState[6].fx = Ifx_Write;
8160 d->fxState[6].offset = OFFB_SSEROUND;
8161 d->fxState[6].size = sizeof(UInt);
8162
8163 /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8164 images are packed back-to-back. If not, the value of
8165 d->fxState[5].size is wrong. */
8166 vassert(16 == sizeof(U128));
8167 vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8168
8169 stmt( IRStmt_Dirty(d) );
8170
8171 goto decode_success;
8172 }
8173
sewardja0e83b02005-01-06 12:36:38 +00008174 /* ------ SSE decoder main ------ */
8175
sewardj9df271d2004-12-31 22:37:42 +00008176 /* Skip parts of the decoder which don't apply given the stated
8177 guest subarchitecture. */
sewardj5117ce12006-01-27 21:20:15 +00008178 if (archinfo->hwcaps == 0/*baseline, no sse at all*/)
sewardj9df271d2004-12-31 22:37:42 +00008179 goto after_sse_decoders;
8180
8181 /* Otherwise we must be doing sse1 or sse2, so we can at least try
8182 for SSE1 here. */
sewardjc9a43662004-11-30 18:51:59 +00008183
sewardjc9a43662004-11-30 18:51:59 +00008184 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00008185 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj129b3d92004-12-05 15:42:05 +00008186 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
sewardjc9a43662004-11-30 18:51:59 +00008187 goto decode_success;
8188 }
8189
sewardj1e6ad742004-12-02 16:16:11 +00008190 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
8191 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
8192 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008193 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
sewardj1e6ad742004-12-02 16:16:11 +00008194 goto decode_success;
8195 }
8196
8197 /* 0F 55 = ANDNPS -- G = (not G) and E */
sewardj636ad762004-12-07 11:16:04 +00008198 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00008199 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00008200 goto decode_success;
8201 }
8202
8203 /* 0F 54 = ANDPS -- G = G and E */
sewardj636ad762004-12-07 11:16:04 +00008204 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00008205 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00008206 goto decode_success;
8207 }
8208
8209 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00008210 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj1e6ad742004-12-02 16:16:11 +00008211 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
8212 goto decode_success;
8213 }
8214
8215 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
8216 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
8217 vassert(sz == 4);
8218 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
8219 goto decode_success;
8220 }
sewardjc9a43662004-11-30 18:51:59 +00008221
sewardjfd226452004-12-07 19:02:18 +00008222 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjc1e7dfc2004-12-05 19:29:45 +00008223 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjfd226452004-12-07 19:02:18 +00008224 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
sewardj67e002d2004-12-02 18:16:33 +00008225 IRTemp argL = newTemp(Ity_F32);
8226 IRTemp argR = newTemp(Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +00008227 modrm = getIByte(delta+2);
8228 if (epartIsReg(modrm)) {
8229 assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
8230 delta += 2+1;
sewardjc1e7dfc2004-12-05 19:29:45 +00008231 DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8232 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00008233 } else {
8234 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8235 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
8236 delta += 2+alen;
sewardjc1e7dfc2004-12-05 19:29:45 +00008237 DIP("[u]comiss %s,%s\n", dis_buf,
8238 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00008239 }
8240 assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
8241
8242 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
8243 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
8244 stmt( IRStmt_Put(
8245 OFFB_CC_DEP1,
8246 binop( Iop_And32,
8247 binop(Iop_CmpF64,
8248 unop(Iop_F32toF64,mkexpr(argL)),
8249 unop(Iop_F32toF64,mkexpr(argR))),
8250 mkU32(0x45)
8251 )));
sewardja3b7e3a2005-04-05 01:54:19 +00008252 /* Set NDEP even though it isn't used. This makes redundant-PUT
8253 elimination of previous stores to this field work better. */
8254 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj67e002d2004-12-02 18:16:33 +00008255 goto decode_success;
8256 }
sewardjc9a43662004-11-30 18:51:59 +00008257
sewardj4cb918d2004-12-03 19:43:31 +00008258 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
8259 half xmm */
sewardjfd226452004-12-07 19:02:18 +00008260 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj4cb918d2004-12-03 19:43:31 +00008261 IRTemp arg64 = newTemp(Ity_I64);
8262 IRTemp rmode = newTemp(Ity_I32);
8263 vassert(sz == 4);
8264
8265 modrm = getIByte(delta+2);
8266 do_MMX_preamble();
8267 if (epartIsReg(modrm)) {
8268 assign( arg64, getMMXReg(eregOfRM(modrm)) );
8269 delta += 2+1;
8270 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8271 nameXMMReg(gregOfRM(modrm)));
8272 } else {
8273 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8274 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8275 delta += 2+alen;
8276 DIP("cvtpi2ps %s,%s\n", dis_buf,
8277 nameXMMReg(gregOfRM(modrm)) );
8278 }
8279
8280 assign( rmode, get_sse_roundingmode() );
8281
8282 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00008283 gregOfRM(modrm), 0,
8284 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00008285 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00008286 unop(Iop_I32StoF64,
sewardj3bca9062004-12-04 14:36:09 +00008287 unop(Iop_64to32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00008288
8289 putXMMRegLane32F(
8290 gregOfRM(modrm), 1,
sewardj3bca9062004-12-04 14:36:09 +00008291 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00008292 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00008293 unop(Iop_I32StoF64,
sewardj3bca9062004-12-04 14:36:09 +00008294 unop(Iop_64HIto32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00008295
8296 goto decode_success;
8297 }
8298
8299 /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
8300 quarter xmm */
8301 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
8302 IRTemp arg32 = newTemp(Ity_I32);
8303 IRTemp rmode = newTemp(Ity_I32);
8304 vassert(sz == 4);
8305
8306 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00008307 if (epartIsReg(modrm)) {
8308 assign( arg32, getIReg(4, eregOfRM(modrm)) );
8309 delta += 3+1;
8310 DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
8311 nameXMMReg(gregOfRM(modrm)));
8312 } else {
8313 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8314 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8315 delta += 3+alen;
8316 DIP("cvtsi2ss %s,%s\n", dis_buf,
8317 nameXMMReg(gregOfRM(modrm)) );
8318 }
8319
8320 assign( rmode, get_sse_roundingmode() );
8321
8322 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00008323 gregOfRM(modrm), 0,
8324 binop(Iop_F64toF32,
8325 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00008326 unop(Iop_I32StoF64, mkexpr(arg32)) ) );
sewardj4cb918d2004-12-03 19:43:31 +00008327
8328 goto decode_success;
8329 }
8330
8331 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8332 I32 in mmx, according to prevailing SSE rounding mode */
8333 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8334 I32 in mmx, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00008335 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj4cb918d2004-12-03 19:43:31 +00008336 IRTemp dst64 = newTemp(Ity_I64);
8337 IRTemp rmode = newTemp(Ity_I32);
8338 IRTemp f32lo = newTemp(Ity_F32);
8339 IRTemp f32hi = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00008340 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00008341
8342 do_MMX_preamble();
8343 modrm = getIByte(delta+2);
8344
8345 if (epartIsReg(modrm)) {
8346 delta += 2+1;
8347 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8348 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
8349 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8350 nameXMMReg(eregOfRM(modrm)),
8351 nameMMXReg(gregOfRM(modrm)));
8352 } else {
8353 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8354 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8355 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
8356 mkexpr(addr),
8357 mkU32(4) )));
8358 delta += 2+alen;
8359 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8360 dis_buf,
8361 nameMMXReg(gregOfRM(modrm)));
8362 }
8363
8364 if (r2zero) {
8365 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8366 } else {
8367 assign( rmode, get_sse_roundingmode() );
8368 }
8369
8370 assign(
8371 dst64,
8372 binop( Iop_32HLto64,
sewardj6c299f32009-12-31 18:00:12 +00008373 binop( Iop_F64toI32S,
sewardj4cb918d2004-12-03 19:43:31 +00008374 mkexpr(rmode),
8375 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
sewardj6c299f32009-12-31 18:00:12 +00008376 binop( Iop_F64toI32S,
sewardj4cb918d2004-12-03 19:43:31 +00008377 mkexpr(rmode),
8378 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8379 )
8380 );
8381
8382 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
8383 goto decode_success;
8384 }
8385
8386 /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
8387 I32 in ireg, according to prevailing SSE rounding mode */
8388 /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
sewardj0b210442005-02-23 13:28:27 +00008389 I32 in ireg, rounding towards zero */
sewardj4cb918d2004-12-03 19:43:31 +00008390 if (insn[0] == 0xF3 && insn[1] == 0x0F
8391 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
8392 IRTemp rmode = newTemp(Ity_I32);
8393 IRTemp f32lo = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00008394 Bool r2zero = toBool(insn[2] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00008395 vassert(sz == 4);
8396
sewardj4cb918d2004-12-03 19:43:31 +00008397 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00008398 if (epartIsReg(modrm)) {
8399 delta += 3+1;
8400 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8401 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8402 nameXMMReg(eregOfRM(modrm)),
8403 nameIReg(4, gregOfRM(modrm)));
8404 } else {
8405 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8406 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8407 delta += 3+alen;
8408 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8409 dis_buf,
8410 nameIReg(4, gregOfRM(modrm)));
8411 }
8412
8413 if (r2zero) {
sewardj7df596b2004-12-06 14:29:12 +00008414 assign( rmode, mkU32((UInt)Irrm_ZERO) );
sewardj4cb918d2004-12-03 19:43:31 +00008415 } else {
8416 assign( rmode, get_sse_roundingmode() );
8417 }
8418
8419 putIReg(4, gregOfRM(modrm),
sewardj6c299f32009-12-31 18:00:12 +00008420 binop( Iop_F64toI32S,
sewardj4cb918d2004-12-03 19:43:31 +00008421 mkexpr(rmode),
8422 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8423 );
8424
8425 goto decode_success;
8426 }
8427
sewardj176a59c2004-12-03 20:08:31 +00008428 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
sewardjfd226452004-12-07 19:02:18 +00008429 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj129b3d92004-12-05 15:42:05 +00008430 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00008431 goto decode_success;
8432 }
8433
8434 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8435 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
8436 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008437 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00008438 goto decode_success;
8439 }
8440
sewardj7df596b2004-12-06 14:29:12 +00008441 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
8442 if (insn[0] == 0x0F && insn[1] == 0xAE
8443 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
8444
8445 IRTemp t64 = newTemp(Ity_I64);
8446 IRTemp ew = newTemp(Ity_I32);
8447
8448 modrm = getIByte(delta+2);
8449 vassert(!epartIsReg(modrm));
8450 vassert(sz == 4);
8451
8452 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8453 delta += 2+alen;
sewardj33dd31b2005-01-08 18:17:32 +00008454 DIP("ldmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00008455
8456 /* The only thing we observe in %mxcsr is the rounding mode.
8457 Therefore, pass the 32-bit value (SSE native-format control
8458 word) to a clean helper, getting back a 64-bit value, the
8459 lower half of which is the SSEROUND value to store, and the
8460 upper half of which is the emulation-warning token which may
8461 be generated.
8462 */
8463 /* ULong x86h_check_ldmxcsr ( UInt ); */
8464 assign( t64, mkIRExprCCall(
8465 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00008466 "x86g_check_ldmxcsr",
8467 &x86g_check_ldmxcsr,
sewardj7df596b2004-12-06 14:29:12 +00008468 mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
8469 )
8470 );
8471
sewardj636ad762004-12-07 11:16:04 +00008472 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
sewardj7df596b2004-12-06 14:29:12 +00008473 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
8474 put_emwarn( mkexpr(ew) );
8475 /* Finally, if an emulation warning was reported, side-exit to
8476 the next insn, reporting the warning, so that Valgrind's
8477 dispatcher sees the warning. */
8478 stmt(
8479 IRStmt_Exit(
8480 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
8481 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00008482 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj7df596b2004-12-06 14:29:12 +00008483 )
8484 );
8485 goto decode_success;
8486 }
8487
sewardjd71ba832006-12-27 01:15:29 +00008488 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8489 /* 0F F7 = MASKMOVQ -- 8x8 masked store */
8490 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF7) {
8491 Bool ok = False;
8492 delta = dis_MMX( &ok, sorb, sz, delta+1 );
8493 if (!ok)
8494 goto decode_failure;
8495 goto decode_success;
8496 }
8497
sewardj176a59c2004-12-03 20:08:31 +00008498 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00008499 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj129b3d92004-12-05 15:42:05 +00008500 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00008501 goto decode_success;
8502 }
8503
8504 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
8505 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
8506 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008507 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00008508 goto decode_success;
8509 }
8510
8511 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00008512 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj129b3d92004-12-05 15:42:05 +00008513 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00008514 goto decode_success;
8515 }
8516
8517 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
8518 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
8519 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008520 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00008521 goto decode_success;
8522 }
sewardj4cb918d2004-12-03 19:43:31 +00008523
sewardj9636b442004-12-04 01:38:37 +00008524 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
sewardjc2feffc2004-12-08 12:31:22 +00008525 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
8526 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
sewardj9636b442004-12-04 01:38:37 +00008527 modrm = getIByte(delta+2);
sewardj9636b442004-12-04 01:38:37 +00008528 if (epartIsReg(modrm)) {
8529 putXMMReg( gregOfRM(modrm),
8530 getXMMReg( eregOfRM(modrm) ));
8531 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8532 nameXMMReg(gregOfRM(modrm)));
8533 delta += 2+1;
8534 } else {
8535 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8536 putXMMReg( gregOfRM(modrm),
8537 loadLE(Ity_V128, mkexpr(addr)) );
8538 DIP("mov[ua]ps %s,%s\n", dis_buf,
8539 nameXMMReg(gregOfRM(modrm)));
8540 delta += 2+alen;
8541 }
8542 goto decode_success;
8543 }
8544
sewardj09f41552004-12-15 12:35:00 +00008545 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
sewardj3ed54842005-08-25 21:34:24 +00008546 /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
8547 if (sz == 4 && insn[0] == 0x0F
8548 && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj09f41552004-12-15 12:35:00 +00008549 modrm = getIByte(delta+2);
sewardj09f41552004-12-15 12:35:00 +00008550 if (epartIsReg(modrm)) {
8551 /* fall through; awaiting test case */
8552 } else {
8553 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8554 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj3ed54842005-08-25 21:34:24 +00008555 DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRM(modrm)),
8556 dis_buf );
sewardj09f41552004-12-15 12:35:00 +00008557 delta += 2+alen;
8558 goto decode_success;
8559 }
8560 }
8561
sewardj0bd7ce62004-12-05 02:47:40 +00008562 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
8563 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00008564 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
sewardj0bd7ce62004-12-05 02:47:40 +00008565 modrm = getIByte(delta+2);
8566 if (epartIsReg(modrm)) {
8567 delta += 2+1;
8568 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
8569 getXMMRegLane64( eregOfRM(modrm), 0 ) );
8570 DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8571 nameXMMReg(gregOfRM(modrm)));
8572 } else {
8573 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8574 delta += 2+alen;
8575 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
8576 loadLE(Ity_I64, mkexpr(addr)) );
8577 DIP("movhps %s,%s\n", dis_buf,
sewardjc2feffc2004-12-08 12:31:22 +00008578 nameXMMReg( gregOfRM(modrm) ));
sewardj0bd7ce62004-12-05 02:47:40 +00008579 }
8580 goto decode_success;
8581 }
8582
8583 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00008584 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
sewardj0bd7ce62004-12-05 02:47:40 +00008585 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00008586 delta += 2;
8587 addr = disAMode ( &alen, sorb, delta, dis_buf );
8588 delta += alen;
8589 storeLE( mkexpr(addr),
8590 getXMMRegLane64( gregOfRM(insn[2]),
8591 1/*upper lane*/ ) );
8592 DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
8593 dis_buf);
8594 goto decode_success;
8595 }
8596 /* else fall through */
8597 }
8598
8599 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
8600 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00008601 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
sewardj0bd7ce62004-12-05 02:47:40 +00008602 modrm = getIByte(delta+2);
8603 if (epartIsReg(modrm)) {
8604 delta += 2+1;
8605 putXMMRegLane64( gregOfRM(modrm),
8606 0/*lower lane*/,
8607 getXMMRegLane64( eregOfRM(modrm), 1 ));
8608 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
8609 nameXMMReg(gregOfRM(modrm)));
8610 } else {
8611 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8612 delta += 2+alen;
8613 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
8614 loadLE(Ity_I64, mkexpr(addr)) );
8615 DIP("movlps %s, %s\n",
8616 dis_buf, nameXMMReg( gregOfRM(modrm) ));
8617 }
8618 goto decode_success;
8619 }
8620
8621 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00008622 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
sewardj0bd7ce62004-12-05 02:47:40 +00008623 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00008624 delta += 2;
8625 addr = disAMode ( &alen, sorb, delta, dis_buf );
8626 delta += alen;
8627 storeLE( mkexpr(addr),
8628 getXMMRegLane64( gregOfRM(insn[2]),
8629 0/*lower lane*/ ) );
8630 DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
8631 dis_buf);
8632 goto decode_success;
8633 }
8634 /* else fall through */
8635 }
8636
sewardj9636b442004-12-04 01:38:37 +00008637 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
8638 to 4 lowest bits of ireg(G) */
8639 if (insn[0] == 0x0F && insn[1] == 0x50) {
sewardj9636b442004-12-04 01:38:37 +00008640 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00008641 if (sz == 4 && epartIsReg(modrm)) {
8642 Int src;
8643 t0 = newTemp(Ity_I32);
8644 t1 = newTemp(Ity_I32);
8645 t2 = newTemp(Ity_I32);
8646 t3 = newTemp(Ity_I32);
sewardj129b3d92004-12-05 15:42:05 +00008647 delta += 2+1;
8648 src = eregOfRM(modrm);
8649 assign( t0, binop( Iop_And32,
8650 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
8651 mkU32(1) ));
8652 assign( t1, binop( Iop_And32,
8653 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
8654 mkU32(2) ));
8655 assign( t2, binop( Iop_And32,
8656 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
8657 mkU32(4) ));
8658 assign( t3, binop( Iop_And32,
8659 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
8660 mkU32(8) ));
8661 putIReg(4, gregOfRM(modrm),
8662 binop(Iop_Or32,
8663 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
8664 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
8665 )
8666 );
8667 DIP("movmskps %s,%s\n", nameXMMReg(src),
8668 nameIReg(4, gregOfRM(modrm)));
8669 goto decode_success;
8670 }
8671 /* else fall through */
sewardj9636b442004-12-04 01:38:37 +00008672 }
8673
8674 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj703d6d62005-05-11 02:55:00 +00008675 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardj9636b442004-12-04 01:38:37 +00008676 if (insn[0] == 0x0F && insn[1] == 0x2B) {
8677 modrm = getIByte(delta+2);
8678 if (!epartIsReg(modrm)) {
8679 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8680 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj703d6d62005-05-11 02:55:00 +00008681 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
8682 dis_buf,
8683 nameXMMReg(gregOfRM(modrm)));
sewardj9636b442004-12-04 01:38:37 +00008684 delta += 2+alen;
8685 goto decode_success;
8686 }
8687 /* else fall through */
8688 }
8689
sewardjc2feffc2004-12-08 12:31:22 +00008690 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
sewardj9636b442004-12-04 01:38:37 +00008691 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
8692 Intel manual does not say anything about the usual business of
8693 the FP reg tags getting trashed whenever an MMX insn happens.
8694 So we just leave them alone.
8695 */
8696 if (insn[0] == 0x0F && insn[1] == 0xE7) {
8697 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00008698 if (sz == 4 && !epartIsReg(modrm)) {
sewardj519d66f2004-12-15 11:57:58 +00008699 /* do_MMX_preamble(); Intel docs don't specify this */
sewardj9636b442004-12-04 01:38:37 +00008700 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8701 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
8702 DIP("movntq %s,%s\n", dis_buf,
8703 nameMMXReg(gregOfRM(modrm)));
8704 delta += 2+alen;
8705 goto decode_success;
8706 }
8707 /* else fall through */
8708 }
8709
8710 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
8711 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
8712 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
8713 vassert(sz == 4);
8714 modrm = getIByte(delta+3);
8715 if (epartIsReg(modrm)) {
8716 putXMMRegLane32( gregOfRM(modrm), 0,
8717 getXMMRegLane32( eregOfRM(modrm), 0 ));
8718 DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8719 nameXMMReg(gregOfRM(modrm)));
8720 delta += 3+1;
8721 } else {
8722 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +00008723 /* zero bits 127:64 */
8724 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
8725 /* zero bits 63:32 */
8726 putXMMRegLane32( gregOfRM(modrm), 1, mkU32(0) );
8727 /* write bits 31:0 */
sewardj9636b442004-12-04 01:38:37 +00008728 putXMMRegLane32( gregOfRM(modrm), 0,
8729 loadLE(Ity_I32, mkexpr(addr)) );
8730 DIP("movss %s,%s\n", dis_buf,
8731 nameXMMReg(gregOfRM(modrm)));
8732 delta += 3+alen;
8733 }
8734 goto decode_success;
8735 }
8736
8737 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
8738 or lo 1/4 xmm). */
8739 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
8740 vassert(sz == 4);
8741 modrm = getIByte(delta+3);
8742 if (epartIsReg(modrm)) {
8743 /* fall through, we don't yet have a test case */
8744 } else {
8745 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8746 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +00008747 getXMMRegLane32(gregOfRM(modrm), 0) );
8748 DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardj9636b442004-12-04 01:38:37 +00008749 dis_buf);
8750 delta += 3+alen;
8751 goto decode_success;
8752 }
8753 }
8754
8755 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00008756 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj129b3d92004-12-05 15:42:05 +00008757 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
sewardj9636b442004-12-04 01:38:37 +00008758 goto decode_success;
8759 }
8760
8761 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
8762 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
8763 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008764 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
sewardj9636b442004-12-04 01:38:37 +00008765 goto decode_success;
8766 }
8767
8768 /* 0F 56 = ORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00008769 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +00008770 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_OrV128 );
sewardj9636b442004-12-04 01:38:37 +00008771 goto decode_success;
8772 }
8773
sewardj3bca9062004-12-04 14:36:09 +00008774 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8775 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00008776 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
sewardjb5452082004-12-04 20:33:02 +00008777 do_MMX_preamble();
8778 delta = dis_MMXop_regmem_to_reg (
8779 sorb, delta+2, insn[1], "pavgb", False );
8780 goto decode_success;
sewardj3bca9062004-12-04 14:36:09 +00008781 }
8782
sewardjb5452082004-12-04 20:33:02 +00008783 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8784 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00008785 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
sewardjb5452082004-12-04 20:33:02 +00008786 do_MMX_preamble();
8787 delta = dis_MMXop_regmem_to_reg (
8788 sorb, delta+2, insn[1], "pavgw", False );
8789 goto decode_success;
8790 }
8791
8792 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8793 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
8794 zero-extend of it in ireg(G). */
8795 if (insn[0] == 0x0F && insn[1] == 0xC5) {
8796 modrm = insn[2];
8797 if (sz == 4 && epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00008798 IRTemp sV = newTemp(Ity_I64);
8799 t5 = newTemp(Ity_I16);
sewardjb5452082004-12-04 20:33:02 +00008800 do_MMX_preamble();
sewardjb9fa69b2004-12-09 23:25:14 +00008801 assign(sV, getMMXReg(eregOfRM(modrm)));
8802 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00008803 switch (insn[3] & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00008804 case 0: assign(t5, mkexpr(t0)); break;
8805 case 1: assign(t5, mkexpr(t1)); break;
8806 case 2: assign(t5, mkexpr(t2)); break;
8807 case 3: assign(t5, mkexpr(t3)); break;
sewardjba89f4c2005-04-07 17:31:27 +00008808 default: vassert(0); /*NOTREACHED*/
sewardjb5452082004-12-04 20:33:02 +00008809 }
sewardjb9fa69b2004-12-09 23:25:14 +00008810 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
sewardjb5452082004-12-04 20:33:02 +00008811 DIP("pextrw $%d,%s,%s\n",
8812 (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
8813 nameIReg(4,gregOfRM(modrm)));
8814 delta += 4;
8815 goto decode_success;
8816 }
8817 /* else fall through */
8818 }
8819
8820 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8821 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
8822 put it into the specified lane of mmx(G). */
sewardje5854d62004-12-09 03:44:34 +00008823 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
8824 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
8825 mmx reg. t4 is the new lane value. t5 is the original
8826 mmx value. t6 is the new mmx value. */
8827 Int lane;
sewardje5854d62004-12-09 03:44:34 +00008828 t4 = newTemp(Ity_I16);
8829 t5 = newTemp(Ity_I64);
8830 t6 = newTemp(Ity_I64);
8831 modrm = insn[2];
8832 do_MMX_preamble();
sewardjb5452082004-12-04 20:33:02 +00008833
sewardje5854d62004-12-09 03:44:34 +00008834 assign(t5, getMMXReg(gregOfRM(modrm)));
sewardjb9fa69b2004-12-09 23:25:14 +00008835 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00008836
sewardje5854d62004-12-09 03:44:34 +00008837 if (epartIsReg(modrm)) {
8838 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +00008839 delta += 3+1;
8840 lane = insn[3+1-1];
sewardje5854d62004-12-09 03:44:34 +00008841 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8842 nameIReg(2,eregOfRM(modrm)),
8843 nameMMXReg(gregOfRM(modrm)));
8844 } else {
sewardj7420b092005-03-13 20:19:19 +00008845 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8846 delta += 3+alen;
8847 lane = insn[3+alen-1];
8848 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
8849 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8850 dis_buf,
8851 nameMMXReg(gregOfRM(modrm)));
sewardjb5452082004-12-04 20:33:02 +00008852 }
sewardje5854d62004-12-09 03:44:34 +00008853
8854 switch (lane & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00008855 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
8856 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
8857 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
8858 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
sewardjba89f4c2005-04-07 17:31:27 +00008859 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +00008860 }
8861 putMMXReg(gregOfRM(modrm), mkexpr(t6));
8862 goto decode_success;
sewardjb5452082004-12-04 20:33:02 +00008863 }
8864
8865 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8866 /* 0F EE = PMAXSW -- 16x4 signed max */
sewardje5854d62004-12-09 03:44:34 +00008867 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
sewardjb5452082004-12-04 20:33:02 +00008868 do_MMX_preamble();
8869 delta = dis_MMXop_regmem_to_reg (
8870 sorb, delta+2, insn[1], "pmaxsw", False );
8871 goto decode_success;
8872 }
8873
8874 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8875 /* 0F DE = PMAXUB -- 8x8 unsigned max */
sewardje5854d62004-12-09 03:44:34 +00008876 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
sewardjb5452082004-12-04 20:33:02 +00008877 do_MMX_preamble();
8878 delta = dis_MMXop_regmem_to_reg (
8879 sorb, delta+2, insn[1], "pmaxub", False );
8880 goto decode_success;
8881 }
8882
8883 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8884 /* 0F EA = PMINSW -- 16x4 signed min */
sewardje5854d62004-12-09 03:44:34 +00008885 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
sewardjb5452082004-12-04 20:33:02 +00008886 do_MMX_preamble();
8887 delta = dis_MMXop_regmem_to_reg (
8888 sorb, delta+2, insn[1], "pminsw", False );
8889 goto decode_success;
8890 }
8891
8892 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8893 /* 0F DA = PMINUB -- 8x8 unsigned min */
sewardje5854d62004-12-09 03:44:34 +00008894 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
sewardjb5452082004-12-04 20:33:02 +00008895 do_MMX_preamble();
8896 delta = dis_MMXop_regmem_to_reg (
8897 sorb, delta+2, insn[1], "pminub", False );
8898 goto decode_success;
8899 }
8900
8901 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8902 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
8903 mmx(G), turn them into a byte, and put zero-extend of it in
8904 ireg(G). */
sewardje5854d62004-12-09 03:44:34 +00008905 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
sewardjb5452082004-12-04 20:33:02 +00008906 modrm = insn[2];
sewardje5854d62004-12-09 03:44:34 +00008907 if (epartIsReg(modrm)) {
sewardjb5452082004-12-04 20:33:02 +00008908 do_MMX_preamble();
8909 t0 = newTemp(Ity_I64);
8910 t1 = newTemp(Ity_I32);
8911 assign(t0, getMMXReg(eregOfRM(modrm)));
8912 assign(t1, mkIRExprCCall(
8913 Ity_I32, 0/*regparms*/,
sewardj38a3f862005-01-13 15:06:51 +00008914 "x86g_calculate_mmx_pmovmskb",
8915 &x86g_calculate_mmx_pmovmskb,
sewardjb5452082004-12-04 20:33:02 +00008916 mkIRExprVec_1(mkexpr(t0))));
8917 putIReg(4, gregOfRM(modrm), mkexpr(t1));
8918 DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8919 nameIReg(4,gregOfRM(modrm)));
8920 delta += 3;
8921 goto decode_success;
8922 }
8923 /* else fall through */
8924 }
8925
sewardj0bd7ce62004-12-05 02:47:40 +00008926 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8927 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
sewardje5854d62004-12-09 03:44:34 +00008928 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
sewardj0bd7ce62004-12-05 02:47:40 +00008929 do_MMX_preamble();
8930 delta = dis_MMXop_regmem_to_reg (
8931 sorb, delta+2, insn[1], "pmuluh", False );
8932 goto decode_success;
8933 }
8934
sewardj7df596b2004-12-06 14:29:12 +00008935 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
8936 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
8937 /* 0F 18 /2 = PREFETCH1 */
8938 /* 0F 18 /3 = PREFETCH2 */
8939 if (insn[0] == 0x0F && insn[1] == 0x18
8940 && !epartIsReg(insn[2])
8941 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
8942 HChar* hintstr = "??";
8943
8944 modrm = getIByte(delta+2);
8945 vassert(!epartIsReg(modrm));
8946
8947 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8948 delta += 2+alen;
8949
8950 switch (gregOfRM(modrm)) {
8951 case 0: hintstr = "nta"; break;
8952 case 1: hintstr = "t0"; break;
8953 case 2: hintstr = "t1"; break;
8954 case 3: hintstr = "t2"; break;
sewardjba89f4c2005-04-07 17:31:27 +00008955 default: vassert(0); /*NOTREACHED*/
sewardj7df596b2004-12-06 14:29:12 +00008956 }
8957
8958 DIP("prefetch%s %s\n", hintstr, dis_buf);
8959 goto decode_success;
8960 }
8961
sewardj85317682006-03-06 14:07:58 +00008962 /* 0F 0D /0 = PREFETCH m8 -- 3DNow! prefetch */
8963 /* 0F 0D /1 = PREFETCHW m8 -- ditto, with some other hint */
8964 if (insn[0] == 0x0F && insn[1] == 0x0D
8965 && !epartIsReg(insn[2])
8966 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 1) {
8967 HChar* hintstr = "??";
8968
8969 modrm = getIByte(delta+2);
8970 vassert(!epartIsReg(modrm));
8971
8972 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8973 delta += 2+alen;
8974
8975 switch (gregOfRM(modrm)) {
8976 case 0: hintstr = ""; break;
8977 case 1: hintstr = "w"; break;
8978 default: vassert(0); /*NOTREACHED*/
8979 }
8980
8981 DIP("prefetch%s %s\n", hintstr, dis_buf);
8982 goto decode_success;
8983 }
8984
sewardj0bd7ce62004-12-05 02:47:40 +00008985 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8986 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
sewardj7b5b9982005-10-04 11:43:37 +00008987 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF6) {
sewardj0bd7ce62004-12-05 02:47:40 +00008988 do_MMX_preamble();
8989 delta = dis_MMXop_regmem_to_reg (
8990 sorb, delta+2, insn[1], "psadbw", False );
8991 goto decode_success;
8992 }
8993
8994 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8995 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
sewardjb9fa69b2004-12-09 23:25:14 +00008996 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
sewardj0bd7ce62004-12-05 02:47:40 +00008997 Int order;
sewardjb9fa69b2004-12-09 23:25:14 +00008998 IRTemp sV, dV, s3, s2, s1, s0;
8999 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9000 sV = newTemp(Ity_I64);
9001 dV = newTemp(Ity_I64);
sewardj0bd7ce62004-12-05 02:47:40 +00009002 do_MMX_preamble();
9003 modrm = insn[2];
9004 if (epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00009005 assign( sV, getMMXReg(eregOfRM(modrm)) );
sewardj0bd7ce62004-12-05 02:47:40 +00009006 order = (Int)insn[3];
9007 delta += 2+2;
9008 DIP("pshufw $%d,%s,%s\n", order,
9009 nameMMXReg(eregOfRM(modrm)),
9010 nameMMXReg(gregOfRM(modrm)));
9011 } else {
9012 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardjb9fa69b2004-12-09 23:25:14 +00009013 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
sewardj0bd7ce62004-12-05 02:47:40 +00009014 order = (Int)insn[2+alen];
9015 delta += 3+alen;
9016 DIP("pshufw $%d,%s,%s\n", order,
9017 dis_buf,
9018 nameMMXReg(gregOfRM(modrm)));
9019 }
sewardjb9fa69b2004-12-09 23:25:14 +00009020 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
sewardj0bd7ce62004-12-05 02:47:40 +00009021
sewardjb9fa69b2004-12-09 23:25:14 +00009022# define SEL(n) \
9023 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9024 assign(dV,
9025 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9026 SEL((order>>2)&3), SEL((order>>0)&3) )
sewardj0bd7ce62004-12-05 02:47:40 +00009027 );
sewardjb9fa69b2004-12-09 23:25:14 +00009028 putMMXReg(gregOfRM(modrm), mkexpr(dV));
sewardj0bd7ce62004-12-05 02:47:40 +00009029# undef SEL
sewardj0bd7ce62004-12-05 02:47:40 +00009030 goto decode_success;
9031 }
9032
9033 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
9034 if (insn[0] == 0x0F && insn[1] == 0x53) {
9035 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00009036 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9037 "rcpps", Iop_Recip32Fx4 );
sewardj0bd7ce62004-12-05 02:47:40 +00009038 goto decode_success;
9039 }
9040
9041 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
9042 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
9043 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00009044 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9045 "rcpss", Iop_Recip32F0x4 );
sewardj0bd7ce62004-12-05 02:47:40 +00009046 goto decode_success;
9047 }
sewardjb5452082004-12-04 20:33:02 +00009048
sewardjc1e7dfc2004-12-05 19:29:45 +00009049 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
9050 if (insn[0] == 0x0F && insn[1] == 0x52) {
9051 vassert(sz == 4);
9052 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9053 "rsqrtps", Iop_RSqrt32Fx4 );
9054 goto decode_success;
9055 }
9056
9057 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
9058 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
9059 vassert(sz == 4);
9060 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9061 "rsqrtss", Iop_RSqrt32F0x4 );
9062 goto decode_success;
9063 }
9064
9065 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
9066 if (insn[0] == 0x0F && insn[1] == 0xAE
sewardjc2feffc2004-12-08 12:31:22 +00009067 && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009068 vassert(sz == 4);
9069 delta += 3;
sewardj3e838932005-01-07 12:09:15 +00009070 /* Insert a memory fence. It's sometimes important that these
9071 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +00009072 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjc1e7dfc2004-12-05 19:29:45 +00009073 DIP("sfence\n");
9074 goto decode_success;
9075 }
9076
9077 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
sewardj008754b2004-12-08 14:37:10 +00009078 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009079 Int select;
9080 IRTemp sV, dV;
9081 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9082 sV = newTemp(Ity_V128);
9083 dV = newTemp(Ity_V128);
9084 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00009085 modrm = insn[2];
9086 assign( dV, getXMMReg(gregOfRM(modrm)) );
9087
9088 if (epartIsReg(modrm)) {
9089 assign( sV, getXMMReg(eregOfRM(modrm)) );
9090 select = (Int)insn[3];
9091 delta += 2+2;
9092 DIP("shufps $%d,%s,%s\n", select,
9093 nameXMMReg(eregOfRM(modrm)),
9094 nameXMMReg(gregOfRM(modrm)));
9095 } else {
9096 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9097 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9098 select = (Int)insn[2+alen];
9099 delta += 3+alen;
9100 DIP("shufps $%d,%s,%s\n", select,
9101 dis_buf,
9102 nameXMMReg(gregOfRM(modrm)));
9103 }
9104
9105 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9106 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9107
9108# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
9109# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9110
9111 putXMMReg(
9112 gregOfRM(modrm),
9113 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
9114 SELD((select>>2)&3), SELD((select>>0)&3) )
9115 );
9116
9117# undef SELD
9118# undef SELS
9119
9120 goto decode_success;
9121 }
9122
9123 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00009124 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009125 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9126 "sqrtps", Iop_Sqrt32Fx4 );
9127 goto decode_success;
9128 }
9129
9130 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9131 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
9132 vassert(sz == 4);
9133 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9134 "sqrtss", Iop_Sqrt32F0x4 );
9135 goto decode_success;
9136 }
9137
sewardja0e83b02005-01-06 12:36:38 +00009138 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
sewardj7df596b2004-12-06 14:29:12 +00009139 if (insn[0] == 0x0F && insn[1] == 0xAE
9140 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
9141 modrm = getIByte(delta+2);
9142 vassert(sz == 4);
9143 vassert(!epartIsReg(modrm));
9144
9145 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9146 delta += 2+alen;
9147
9148 /* Fake up a native SSE mxcsr word. The only thing it depends
9149 on is SSEROUND[1:0], so call a clean helper to cook it up.
9150 */
9151 /* UInt x86h_create_mxcsr ( UInt sseround ) */
sewardj33dd31b2005-01-08 18:17:32 +00009152 DIP("stmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00009153 storeLE( mkexpr(addr),
9154 mkIRExprCCall(
9155 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00009156 "x86g_create_mxcsr", &x86g_create_mxcsr,
sewardja0e83b02005-01-06 12:36:38 +00009157 mkIRExprVec_1( get_sse_roundingmode() )
sewardj7df596b2004-12-06 14:29:12 +00009158 )
9159 );
9160 goto decode_success;
9161 }
9162
sewardjc1e7dfc2004-12-05 19:29:45 +00009163 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00009164 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009165 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
9166 goto decode_success;
9167 }
9168
sewardj008754b2004-12-08 14:37:10 +00009169 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
sewardjc1e7dfc2004-12-05 19:29:45 +00009170 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
9171 vassert(sz == 4);
9172 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
9173 goto decode_success;
9174 }
9175
9176 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9177 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9178 /* These just appear to be special cases of SHUFPS */
sewardj008754b2004-12-08 14:37:10 +00009179 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009180 IRTemp sV, dV;
9181 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardj2d49b432005-02-01 00:37:06 +00009182 Bool hi = toBool(insn[1] == 0x15);
sewardjc1e7dfc2004-12-05 19:29:45 +00009183 sV = newTemp(Ity_V128);
9184 dV = newTemp(Ity_V128);
9185 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00009186 modrm = insn[2];
9187 assign( dV, getXMMReg(gregOfRM(modrm)) );
9188
9189 if (epartIsReg(modrm)) {
9190 assign( sV, getXMMReg(eregOfRM(modrm)) );
9191 delta += 2+1;
9192 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9193 nameXMMReg(eregOfRM(modrm)),
9194 nameXMMReg(gregOfRM(modrm)));
9195 } else {
9196 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9197 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9198 delta += 2+alen;
9199 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9200 dis_buf,
9201 nameXMMReg(gregOfRM(modrm)));
9202 }
9203
9204 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9205 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9206
9207 if (hi) {
9208 putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
9209 } else {
9210 putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
9211 }
9212
9213 goto decode_success;
9214 }
9215
9216 /* 0F 57 = XORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00009217 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +00009218 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_XorV128 );
sewardjc1e7dfc2004-12-05 19:29:45 +00009219 goto decode_success;
9220 }
9221
sewardj636ad762004-12-07 11:16:04 +00009222 /* ---------------------------------------------------- */
9223 /* --- end of the SSE decoder. --- */
9224 /* ---------------------------------------------------- */
9225
9226 /* ---------------------------------------------------- */
9227 /* --- start of the SSE2 decoder. --- */
9228 /* ---------------------------------------------------- */
9229
sewardj9df271d2004-12-31 22:37:42 +00009230 /* Skip parts of the decoder which don't apply given the stated
9231 guest subarchitecture. */
sewardj5117ce12006-01-27 21:20:15 +00009232 if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
9233 goto after_sse_decoders; /* no SSE2 capabilities */
sewardj9df271d2004-12-31 22:37:42 +00009234
sewardj636ad762004-12-07 11:16:04 +00009235 insn = (UChar*)&guest_code[delta];
9236
9237 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9238 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
9239 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
9240 goto decode_success;
9241 }
9242
9243 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9244 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
9245 vassert(sz == 4);
9246 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
9247 goto decode_success;
9248 }
9249
9250 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9251 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00009252 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00009253 goto decode_success;
9254 }
9255
9256 /* 66 0F 54 = ANDPD -- G = G and E */
9257 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00009258 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00009259 goto decode_success;
9260 }
9261
sewardjfd226452004-12-07 19:02:18 +00009262 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9263 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
9264 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
9265 goto decode_success;
9266 }
9267
9268 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9269 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
9270 vassert(sz == 4);
9271 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
9272 goto decode_success;
9273 }
9274
9275 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
9276 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
9277 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9278 IRTemp argL = newTemp(Ity_F64);
9279 IRTemp argR = newTemp(Ity_F64);
9280 modrm = getIByte(delta+2);
9281 if (epartIsReg(modrm)) {
9282 assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
9283 delta += 2+1;
9284 DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9285 nameXMMReg(gregOfRM(modrm)) );
9286 } else {
9287 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9288 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9289 delta += 2+alen;
9290 DIP("[u]comisd %s,%s\n", dis_buf,
9291 nameXMMReg(gregOfRM(modrm)) );
9292 }
9293 assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
9294
9295 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
9296 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
9297 stmt( IRStmt_Put(
9298 OFFB_CC_DEP1,
9299 binop( Iop_And32,
9300 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
9301 mkU32(0x45)
9302 )));
sewardja3b7e3a2005-04-05 01:54:19 +00009303 /* Set NDEP even though it isn't used. This makes redundant-PUT
9304 elimination of previous stores to this field work better. */
9305 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjfd226452004-12-07 19:02:18 +00009306 goto decode_success;
9307 }
9308
9309 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9310 F64 in xmm(G) */
9311 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
9312 IRTemp arg64 = newTemp(Ity_I64);
9313 vassert(sz == 4);
9314
9315 modrm = getIByte(delta+3);
9316 if (epartIsReg(modrm)) {
9317 assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
9318 delta += 3+1;
9319 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9320 nameXMMReg(gregOfRM(modrm)));
9321 } else {
9322 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9323 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9324 delta += 3+alen;
9325 DIP("cvtdq2pd %s,%s\n", dis_buf,
9326 nameXMMReg(gregOfRM(modrm)) );
9327 }
9328
9329 putXMMRegLane64F(
9330 gregOfRM(modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +00009331 unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)))
sewardjfd226452004-12-07 19:02:18 +00009332 );
9333
9334 putXMMRegLane64F(
9335 gregOfRM(modrm), 1,
sewardj6c299f32009-12-31 18:00:12 +00009336 unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)))
sewardjfd226452004-12-07 19:02:18 +00009337 );
9338
9339 goto decode_success;
9340 }
9341
9342 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9343 xmm(G) */
9344 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
9345 IRTemp argV = newTemp(Ity_V128);
9346 IRTemp rmode = newTemp(Ity_I32);
9347
9348 modrm = getIByte(delta+2);
9349 if (epartIsReg(modrm)) {
9350 assign( argV, getXMMReg(eregOfRM(modrm)) );
9351 delta += 2+1;
9352 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9353 nameXMMReg(gregOfRM(modrm)));
9354 } else {
9355 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9356 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9357 delta += 2+alen;
9358 DIP("cvtdq2ps %s,%s\n", dis_buf,
9359 nameXMMReg(gregOfRM(modrm)) );
9360 }
9361
9362 assign( rmode, get_sse_roundingmode() );
9363 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9364
9365# define CVT(_t) binop( Iop_F64toF32, \
9366 mkexpr(rmode), \
sewardj6c299f32009-12-31 18:00:12 +00009367 unop(Iop_I32StoF64,mkexpr(_t)))
sewardjfd226452004-12-07 19:02:18 +00009368
9369 putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
9370 putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
9371 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9372 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9373
9374# undef CVT
9375
9376 goto decode_success;
9377 }
9378
9379 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9380 lo half xmm(G), and zero upper half */
9381 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
9382 IRTemp argV = newTemp(Ity_V128);
9383 IRTemp rmode = newTemp(Ity_I32);
9384 vassert(sz == 4);
9385
9386 modrm = getIByte(delta+3);
9387 if (epartIsReg(modrm)) {
9388 assign( argV, getXMMReg(eregOfRM(modrm)) );
9389 delta += 3+1;
9390 DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9391 nameXMMReg(gregOfRM(modrm)));
9392 } else {
9393 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9394 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9395 delta += 3+alen;
9396 DIP("cvtpd2dq %s,%s\n", dis_buf,
9397 nameXMMReg(gregOfRM(modrm)) );
9398 }
9399
9400 assign( rmode, get_sse_roundingmode() );
9401 t0 = newTemp(Ity_F64);
9402 t1 = newTemp(Ity_F64);
9403 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009404 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009405 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009406 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009407
sewardj6c299f32009-12-31 18:00:12 +00009408# define CVT(_t) binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +00009409 mkexpr(rmode), \
9410 mkexpr(_t) )
9411
9412 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9413 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9414 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9415 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9416
9417# undef CVT
9418
9419 goto decode_success;
9420 }
9421
9422 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9423 I32 in mmx, according to prevailing SSE rounding mode */
9424 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9425 I32 in mmx, rounding towards zero */
9426 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9427 IRTemp dst64 = newTemp(Ity_I64);
9428 IRTemp rmode = newTemp(Ity_I32);
9429 IRTemp f64lo = newTemp(Ity_F64);
9430 IRTemp f64hi = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00009431 Bool r2zero = toBool(insn[1] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00009432
9433 do_MMX_preamble();
9434 modrm = getIByte(delta+2);
9435
9436 if (epartIsReg(modrm)) {
9437 delta += 2+1;
9438 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9439 assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
9440 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9441 nameXMMReg(eregOfRM(modrm)),
9442 nameMMXReg(gregOfRM(modrm)));
9443 } else {
9444 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9445 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9446 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
9447 mkexpr(addr),
9448 mkU32(8) )));
9449 delta += 2+alen;
9450 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9451 dis_buf,
9452 nameMMXReg(gregOfRM(modrm)));
9453 }
9454
9455 if (r2zero) {
9456 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9457 } else {
9458 assign( rmode, get_sse_roundingmode() );
9459 }
9460
9461 assign(
9462 dst64,
9463 binop( Iop_32HLto64,
sewardj6c299f32009-12-31 18:00:12 +00009464 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64hi) ),
9465 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo) )
sewardjfd226452004-12-07 19:02:18 +00009466 )
9467 );
9468
9469 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
9470 goto decode_success;
9471 }
9472
9473 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9474 lo half xmm(G), and zero upper half */
9475 /* Note, this is practically identical to CVTPD2DQ. It would have
9476 been nicer to merge them together, but the insn[] offsets differ
9477 by one. */
9478 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
9479 IRTemp argV = newTemp(Ity_V128);
9480 IRTemp rmode = newTemp(Ity_I32);
9481
9482 modrm = getIByte(delta+2);
9483 if (epartIsReg(modrm)) {
9484 assign( argV, getXMMReg(eregOfRM(modrm)) );
9485 delta += 2+1;
9486 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9487 nameXMMReg(gregOfRM(modrm)));
9488 } else {
9489 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9490 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9491 delta += 2+alen;
9492 DIP("cvtpd2ps %s,%s\n", dis_buf,
9493 nameXMMReg(gregOfRM(modrm)) );
9494 }
9495
9496 assign( rmode, get_sse_roundingmode() );
9497 t0 = newTemp(Ity_F64);
9498 t1 = newTemp(Ity_F64);
9499 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009500 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009501 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009502 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009503
9504# define CVT(_t) binop( Iop_F64toF32, \
9505 mkexpr(rmode), \
9506 mkexpr(_t) )
9507
9508 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9509 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9510 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9511 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9512
9513# undef CVT
9514
9515 goto decode_success;
9516 }
9517
9518 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9519 xmm(G) */
9520 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
9521 IRTemp arg64 = newTemp(Ity_I64);
9522
9523 modrm = getIByte(delta+2);
sewardjfd226452004-12-07 19:02:18 +00009524 if (epartIsReg(modrm)) {
sewardj30a20e92010-02-21 20:40:53 +00009525 /* Only switch to MMX mode if the source is a MMX register.
9526 This is inconsistent with all other instructions which
9527 convert between XMM and (M64 or MMX), which always switch
9528 to MMX mode even if 64-bit operand is M64 and not MMX. At
9529 least, that's what the Intel docs seem to me to say.
9530 Fixes #210264. */
9531 do_MMX_preamble();
sewardjfd226452004-12-07 19:02:18 +00009532 assign( arg64, getMMXReg(eregOfRM(modrm)) );
9533 delta += 2+1;
9534 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9535 nameXMMReg(gregOfRM(modrm)));
9536 } else {
9537 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9538 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9539 delta += 2+alen;
9540 DIP("cvtpi2pd %s,%s\n", dis_buf,
9541 nameXMMReg(gregOfRM(modrm)) );
9542 }
9543
9544 putXMMRegLane64F(
9545 gregOfRM(modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +00009546 unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)) )
sewardjfd226452004-12-07 19:02:18 +00009547 );
9548
9549 putXMMRegLane64F(
9550 gregOfRM(modrm), 1,
sewardj6c299f32009-12-31 18:00:12 +00009551 unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)) )
sewardjfd226452004-12-07 19:02:18 +00009552 );
9553
9554 goto decode_success;
9555 }
9556
9557 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9558 xmm(G) */
9559 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
9560 IRTemp argV = newTemp(Ity_V128);
9561 IRTemp rmode = newTemp(Ity_I32);
9562
9563 modrm = getIByte(delta+2);
9564 if (epartIsReg(modrm)) {
9565 assign( argV, getXMMReg(eregOfRM(modrm)) );
9566 delta += 2+1;
9567 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9568 nameXMMReg(gregOfRM(modrm)));
9569 } else {
9570 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9571 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9572 delta += 2+alen;
9573 DIP("cvtps2dq %s,%s\n", dis_buf,
9574 nameXMMReg(gregOfRM(modrm)) );
9575 }
9576
9577 assign( rmode, get_sse_roundingmode() );
9578 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9579
9580 /* This is less than ideal. If it turns out to be a performance
9581 bottleneck it can be improved. */
9582# define CVT(_t) \
sewardj6c299f32009-12-31 18:00:12 +00009583 binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +00009584 mkexpr(rmode), \
9585 unop( Iop_F32toF64, \
9586 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9587
9588 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9589 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9590 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9591 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9592
9593# undef CVT
9594
9595 goto decode_success;
9596 }
9597
9598 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9599 F64 in xmm(G). */
9600 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
9601 IRTemp f32lo = newTemp(Ity_F32);
9602 IRTemp f32hi = newTemp(Ity_F32);
9603
9604 modrm = getIByte(delta+2);
9605 if (epartIsReg(modrm)) {
9606 assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
9607 assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
9608 delta += 2+1;
9609 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9610 nameXMMReg(gregOfRM(modrm)));
9611 } else {
9612 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9613 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9614 assign( f32hi, loadLE(Ity_F32,
9615 binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
9616 delta += 2+alen;
9617 DIP("cvtps2pd %s,%s\n", dis_buf,
9618 nameXMMReg(gregOfRM(modrm)) );
9619 }
9620
9621 putXMMRegLane64F( gregOfRM(modrm), 1,
9622 unop(Iop_F32toF64, mkexpr(f32hi)) );
9623 putXMMRegLane64F( gregOfRM(modrm), 0,
9624 unop(Iop_F32toF64, mkexpr(f32lo)) );
9625
9626 goto decode_success;
9627 }
9628
9629 /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
9630 I32 in ireg, according to prevailing SSE rounding mode */
9631 /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
sewardj0b210442005-02-23 13:28:27 +00009632 I32 in ireg, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00009633 if (insn[0] == 0xF2 && insn[1] == 0x0F
9634 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
9635 IRTemp rmode = newTemp(Ity_I32);
9636 IRTemp f64lo = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00009637 Bool r2zero = toBool(insn[2] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00009638 vassert(sz == 4);
9639
9640 modrm = getIByte(delta+3);
9641 if (epartIsReg(modrm)) {
9642 delta += 3+1;
9643 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9644 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9645 nameXMMReg(eregOfRM(modrm)),
9646 nameIReg(4, gregOfRM(modrm)));
9647 } else {
9648 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9649 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9650 delta += 3+alen;
9651 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9652 dis_buf,
9653 nameIReg(4, gregOfRM(modrm)));
9654 }
9655
9656 if (r2zero) {
9657 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9658 } else {
9659 assign( rmode, get_sse_roundingmode() );
9660 }
9661
9662 putIReg(4, gregOfRM(modrm),
sewardj6c299f32009-12-31 18:00:12 +00009663 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo)) );
sewardjfd226452004-12-07 19:02:18 +00009664
9665 goto decode_success;
9666 }
9667
9668 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
9669 low 1/4 xmm(G), according to prevailing SSE rounding mode */
9670 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
9671 IRTemp rmode = newTemp(Ity_I32);
9672 IRTemp f64lo = newTemp(Ity_F64);
9673 vassert(sz == 4);
9674
9675 modrm = getIByte(delta+3);
9676 if (epartIsReg(modrm)) {
9677 delta += 3+1;
9678 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9679 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9680 nameXMMReg(gregOfRM(modrm)));
9681 } else {
9682 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9683 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9684 delta += 3+alen;
9685 DIP("cvtsd2ss %s,%s\n", dis_buf,
9686 nameXMMReg(gregOfRM(modrm)));
9687 }
9688
9689 assign( rmode, get_sse_roundingmode() );
9690 putXMMRegLane32F(
9691 gregOfRM(modrm), 0,
9692 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
9693 );
9694
9695 goto decode_success;
9696 }
9697
9698 /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
9699 half xmm */
9700 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
9701 IRTemp arg32 = newTemp(Ity_I32);
9702 vassert(sz == 4);
9703
9704 modrm = getIByte(delta+3);
sewardjfd226452004-12-07 19:02:18 +00009705 if (epartIsReg(modrm)) {
9706 assign( arg32, getIReg(4, eregOfRM(modrm)) );
9707 delta += 3+1;
9708 DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
9709 nameXMMReg(gregOfRM(modrm)));
9710 } else {
9711 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9712 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
9713 delta += 3+alen;
9714 DIP("cvtsi2sd %s,%s\n", dis_buf,
9715 nameXMMReg(gregOfRM(modrm)) );
9716 }
9717
9718 putXMMRegLane64F(
9719 gregOfRM(modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +00009720 unop(Iop_I32StoF64, mkexpr(arg32)) );
sewardjfd226452004-12-07 19:02:18 +00009721
9722 goto decode_success;
9723 }
9724
9725 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
9726 low half xmm(G) */
9727 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
9728 IRTemp f32lo = newTemp(Ity_F32);
9729 vassert(sz == 4);
9730
9731 modrm = getIByte(delta+3);
9732 if (epartIsReg(modrm)) {
9733 delta += 3+1;
9734 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
9735 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9736 nameXMMReg(gregOfRM(modrm)));
9737 } else {
9738 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9739 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
9740 delta += 3+alen;
9741 DIP("cvtss2sd %s,%s\n", dis_buf,
9742 nameXMMReg(gregOfRM(modrm)));
9743 }
9744
9745 putXMMRegLane64F( gregOfRM(modrm), 0,
9746 unop( Iop_F32toF64, mkexpr(f32lo) ) );
9747
9748 goto decode_success;
9749 }
9750
9751 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9752 lo half xmm(G), and zero upper half, rounding towards zero */
9753 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
9754 IRTemp argV = newTemp(Ity_V128);
9755 IRTemp rmode = newTemp(Ity_I32);
9756
9757 modrm = getIByte(delta+2);
9758 if (epartIsReg(modrm)) {
9759 assign( argV, getXMMReg(eregOfRM(modrm)) );
9760 delta += 2+1;
9761 DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9762 nameXMMReg(gregOfRM(modrm)));
9763 } else {
9764 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9765 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9766 delta += 2+alen;
9767 DIP("cvttpd2dq %s,%s\n", dis_buf,
9768 nameXMMReg(gregOfRM(modrm)) );
9769 }
9770
9771 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9772
9773 t0 = newTemp(Ity_F64);
9774 t1 = newTemp(Ity_F64);
9775 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009776 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009777 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009778 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009779
sewardj6c299f32009-12-31 18:00:12 +00009780# define CVT(_t) binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +00009781 mkexpr(rmode), \
9782 mkexpr(_t) )
9783
9784 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9785 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9786 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9787 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9788
9789# undef CVT
9790
9791 goto decode_success;
9792 }
9793
9794 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9795 xmm(G), rounding towards zero */
9796 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
9797 IRTemp argV = newTemp(Ity_V128);
9798 IRTemp rmode = newTemp(Ity_I32);
9799 vassert(sz == 4);
9800
9801 modrm = getIByte(delta+3);
9802 if (epartIsReg(modrm)) {
9803 assign( argV, getXMMReg(eregOfRM(modrm)) );
9804 delta += 3+1;
9805 DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9806 nameXMMReg(gregOfRM(modrm)));
9807 } else {
9808 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9809 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9810 delta += 3+alen;
9811 DIP("cvttps2dq %s,%s\n", dis_buf,
9812 nameXMMReg(gregOfRM(modrm)) );
9813 }
9814
9815 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9816 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9817
9818 /* This is less than ideal. If it turns out to be a performance
9819 bottleneck it can be improved. */
9820# define CVT(_t) \
sewardj6c299f32009-12-31 18:00:12 +00009821 binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +00009822 mkexpr(rmode), \
9823 unop( Iop_F32toF64, \
9824 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9825
9826 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9827 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9828 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9829 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9830
9831# undef CVT
9832
9833 goto decode_success;
9834 }
9835
9836 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
9837 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
9838 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
9839 goto decode_success;
9840 }
9841
sewardjc2feffc2004-12-08 12:31:22 +00009842 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
9843 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5E) {
9844 vassert(sz == 4);
9845 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "divsd", Iop_Div64F0x2 );
9846 goto decode_success;
9847 }
9848
9849 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
9850 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
9851 if (insn[0] == 0x0F && insn[1] == 0xAE
9852 && epartIsReg(insn[2])
9853 && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
9854 vassert(sz == 4);
9855 delta += 3;
sewardj3e838932005-01-07 12:09:15 +00009856 /* Insert a memory fence. It's sometimes important that these
9857 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +00009858 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjc2feffc2004-12-08 12:31:22 +00009859 DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
9860 goto decode_success;
9861 }
9862
9863 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
9864 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
9865 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
9866 goto decode_success;
9867 }
9868
9869 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
9870 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5F) {
9871 vassert(sz == 4);
9872 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "maxsd", Iop_Max64F0x2 );
9873 goto decode_success;
9874 }
9875
9876 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
9877 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
9878 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
9879 goto decode_success;
9880 }
9881
9882 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
9883 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) {
9884 vassert(sz == 4);
9885 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 );
9886 goto decode_success;
9887 }
9888
9889 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
9890 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
9891 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
9892 if (sz == 2 && insn[0] == 0x0F
9893 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
9894 HChar* wot = insn[1]==0x28 ? "apd" :
9895 insn[1]==0x10 ? "upd" : "dqa";
9896 modrm = getIByte(delta+2);
9897 if (epartIsReg(modrm)) {
9898 putXMMReg( gregOfRM(modrm),
9899 getXMMReg( eregOfRM(modrm) ));
9900 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)),
9901 nameXMMReg(gregOfRM(modrm)));
9902 delta += 2+1;
9903 } else {
9904 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9905 putXMMReg( gregOfRM(modrm),
9906 loadLE(Ity_V128, mkexpr(addr)) );
9907 DIP("mov%s %s,%s\n", wot, dis_buf,
9908 nameXMMReg(gregOfRM(modrm)));
9909 delta += 2+alen;
9910 }
9911 goto decode_success;
9912 }
9913
sewardj95535fe2004-12-15 17:42:58 +00009914 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj1c318772005-03-19 14:27:04 +00009915 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
9916 if (sz == 2 && insn[0] == 0x0F
9917 && (insn[1] == 0x29 || insn[1] == 0x11)) {
9918 HChar* wot = insn[1]==0x29 ? "apd" : "upd";
sewardj95535fe2004-12-15 17:42:58 +00009919 modrm = getIByte(delta+2);
9920 if (epartIsReg(modrm)) {
9921 /* fall through; awaiting test case */
9922 } else {
9923 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9924 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj1c318772005-03-19 14:27:04 +00009925 DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRM(modrm)),
9926 dis_buf );
sewardj95535fe2004-12-15 17:42:58 +00009927 delta += 2+alen;
9928 goto decode_success;
9929 }
9930 }
9931
sewardjc2feffc2004-12-08 12:31:22 +00009932 /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
9933 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
9934 modrm = getIByte(delta+2);
9935 if (epartIsReg(modrm)) {
9936 delta += 2+1;
9937 putXMMReg(
9938 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009939 unop( Iop_32UtoV128, getIReg(4, eregOfRM(modrm)) )
sewardjc2feffc2004-12-08 12:31:22 +00009940 );
9941 DIP("movd %s, %s\n",
9942 nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
9943 } else {
9944 addr = disAMode( &alen, sorb, delta+2, dis_buf );
9945 delta += 2+alen;
9946 putXMMReg(
9947 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009948 unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
sewardjc2feffc2004-12-08 12:31:22 +00009949 );
9950 DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
9951 }
9952 goto decode_success;
9953 }
9954
9955 /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
9956 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
9957 modrm = getIByte(delta+2);
9958 if (epartIsReg(modrm)) {
9959 delta += 2+1;
9960 putIReg( 4, eregOfRM(modrm),
9961 getXMMRegLane32(gregOfRM(modrm), 0) );
9962 DIP("movd %s, %s\n",
9963 nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
9964 } else {
9965 addr = disAMode( &alen, sorb, delta+2, dis_buf );
9966 delta += 2+alen;
9967 storeLE( mkexpr(addr),
9968 getXMMRegLane32(gregOfRM(modrm), 0) );
9969 DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
9970 }
9971 goto decode_success;
9972 }
9973
9974 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
9975 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
9976 modrm = getIByte(delta+2);
9977 if (epartIsReg(modrm)) {
9978 delta += 2+1;
9979 putXMMReg( eregOfRM(modrm),
9980 getXMMReg(gregOfRM(modrm)) );
9981 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
9982 nameXMMReg(eregOfRM(modrm)));
9983 } else {
9984 addr = disAMode( &alen, sorb, delta+2, dis_buf );
9985 delta += 2+alen;
9986 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9987 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
9988 }
9989 goto decode_success;
9990 }
9991
9992 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
9993 /* Unfortunately can't simply use the MOVDQA case since the
9994 prefix lengths are different (66 vs F3) */
9995 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
9996 vassert(sz == 4);
9997 modrm = getIByte(delta+3);
9998 if (epartIsReg(modrm)) {
9999 putXMMReg( gregOfRM(modrm),
10000 getXMMReg( eregOfRM(modrm) ));
10001 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10002 nameXMMReg(gregOfRM(modrm)));
10003 delta += 3+1;
10004 } else {
10005 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10006 putXMMReg( gregOfRM(modrm),
10007 loadLE(Ity_V128, mkexpr(addr)) );
10008 DIP("movdqu %s,%s\n", dis_buf,
10009 nameXMMReg(gregOfRM(modrm)));
10010 delta += 3+alen;
10011 }
10012 goto decode_success;
10013 }
10014
10015 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
10016 /* Unfortunately can't simply use the MOVDQA case since the
10017 prefix lengths are different (66 vs F3) */
10018 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
10019 vassert(sz == 4);
10020 modrm = getIByte(delta+3);
10021 if (epartIsReg(modrm)) {
10022 delta += 3+1;
10023 putXMMReg( eregOfRM(modrm),
10024 getXMMReg(gregOfRM(modrm)) );
10025 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10026 nameXMMReg(eregOfRM(modrm)));
10027 } else {
10028 addr = disAMode( &alen, sorb, delta+3, dis_buf );
10029 delta += 3+alen;
10030 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10031 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10032 }
10033 goto decode_success;
10034 }
10035
10036 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
10037 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
10038 vassert(sz == 4);
10039 modrm = getIByte(delta+3);
10040 if (epartIsReg(modrm)) {
10041 do_MMX_preamble();
10042 putMMXReg( gregOfRM(modrm),
10043 getXMMRegLane64( eregOfRM(modrm), 0 ));
10044 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10045 nameMMXReg(gregOfRM(modrm)));
10046 delta += 3+1;
10047 goto decode_success;
10048 } else {
10049 /* fall through, apparently no mem case for this insn */
10050 }
10051 }
10052
10053 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
10054 /* These seems identical to MOVHPS. This instruction encoding is
10055 completely crazy. */
10056 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
10057 modrm = getIByte(delta+2);
10058 if (epartIsReg(modrm)) {
10059 /* fall through; apparently reg-reg is not possible */
10060 } else {
10061 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10062 delta += 2+alen;
10063 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
10064 loadLE(Ity_I64, mkexpr(addr)) );
10065 DIP("movhpd %s,%s\n", dis_buf,
10066 nameXMMReg( gregOfRM(modrm) ));
10067 goto decode_success;
10068 }
10069 }
10070
10071 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
10072 /* Again, this seems identical to MOVHPS. */
10073 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
10074 if (!epartIsReg(insn[2])) {
10075 delta += 2;
10076 addr = disAMode ( &alen, sorb, delta, dis_buf );
10077 delta += alen;
10078 storeLE( mkexpr(addr),
10079 getXMMRegLane64( gregOfRM(insn[2]),
10080 1/*upper lane*/ ) );
10081 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
10082 dis_buf);
10083 goto decode_success;
10084 }
10085 /* else fall through */
10086 }
10087
10088 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
10089 /* Identical to MOVLPS ? */
10090 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x12) {
10091 modrm = getIByte(delta+2);
10092 if (epartIsReg(modrm)) {
10093 /* fall through; apparently reg-reg is not possible */
10094 } else {
10095 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10096 delta += 2+alen;
10097 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
10098 loadLE(Ity_I64, mkexpr(addr)) );
10099 DIP("movlpd %s, %s\n",
10100 dis_buf, nameXMMReg( gregOfRM(modrm) ));
10101 goto decode_success;
10102 }
10103 }
10104
10105 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
10106 /* Identical to MOVLPS ? */
10107 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
10108 if (!epartIsReg(insn[2])) {
10109 delta += 2;
10110 addr = disAMode ( &alen, sorb, delta, dis_buf );
10111 delta += alen;
10112 storeLE( mkexpr(addr),
10113 getXMMRegLane64( gregOfRM(insn[2]),
10114 0/*lower lane*/ ) );
10115 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
10116 dis_buf);
10117 goto decode_success;
10118 }
10119 /* else fall through */
10120 }
10121
10122 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10123 2 lowest bits of ireg(G) */
10124 if (insn[0] == 0x0F && insn[1] == 0x50) {
10125 modrm = getIByte(delta+2);
10126 if (sz == 2 && epartIsReg(modrm)) {
10127 Int src;
10128 t0 = newTemp(Ity_I32);
10129 t1 = newTemp(Ity_I32);
10130 delta += 2+1;
10131 src = eregOfRM(modrm);
10132 assign( t0, binop( Iop_And32,
10133 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10134 mkU32(1) ));
10135 assign( t1, binop( Iop_And32,
10136 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10137 mkU32(2) ));
10138 putIReg(4, gregOfRM(modrm),
10139 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10140 );
10141 DIP("movmskpd %s,%s\n", nameXMMReg(src),
10142 nameIReg(4, gregOfRM(modrm)));
10143 goto decode_success;
10144 }
10145 /* else fall through */
10146 }
10147
sewardjd71ba832006-12-27 01:15:29 +000010148 /* 66 0F F7 = MASKMOVDQU -- store selected bytes of double quadword */
10149 if (insn[0] == 0x0F && insn[1] == 0xF7) {
10150 modrm = getIByte(delta+2);
10151 if (sz == 2 && epartIsReg(modrm)) {
10152 IRTemp regD = newTemp(Ity_V128);
10153 IRTemp mask = newTemp(Ity_V128);
10154 IRTemp olddata = newTemp(Ity_V128);
10155 IRTemp newdata = newTemp(Ity_V128);
10156 addr = newTemp(Ity_I32);
10157
10158 assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
10159 assign( regD, getXMMReg( gregOfRM(modrm) ));
10160
10161 /* Unfortunately can't do the obvious thing with SarN8x16
10162 here since that can't be re-emitted as SSE2 code - no such
10163 insn. */
10164 assign(
10165 mask,
10166 binop(Iop_64HLtoV128,
10167 binop(Iop_SarN8x8,
10168 getXMMRegLane64( eregOfRM(modrm), 1 ),
10169 mkU8(7) ),
10170 binop(Iop_SarN8x8,
10171 getXMMRegLane64( eregOfRM(modrm), 0 ),
10172 mkU8(7) ) ));
10173 assign( olddata, loadLE( Ity_V128, mkexpr(addr) ));
10174 assign( newdata,
10175 binop(Iop_OrV128,
10176 binop(Iop_AndV128,
10177 mkexpr(regD),
10178 mkexpr(mask) ),
10179 binop(Iop_AndV128,
10180 mkexpr(olddata),
10181 unop(Iop_NotV128, mkexpr(mask)))) );
10182 storeLE( mkexpr(addr), mkexpr(newdata) );
10183
10184 delta += 2+1;
10185 DIP("maskmovdqu %s,%s\n", nameXMMReg( eregOfRM(modrm) ),
10186 nameXMMReg( gregOfRM(modrm) ) );
10187 goto decode_success;
10188 }
10189 /* else fall through */
10190 }
10191
sewardjc2feffc2004-12-08 12:31:22 +000010192 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10193 if (insn[0] == 0x0F && insn[1] == 0xE7) {
10194 modrm = getIByte(delta+2);
10195 if (sz == 2 && !epartIsReg(modrm)) {
10196 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10197 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10198 DIP("movntdq %s,%s\n", dis_buf,
10199 nameXMMReg(gregOfRM(modrm)));
10200 delta += 2+alen;
10201 goto decode_success;
10202 }
10203 /* else fall through */
10204 }
10205
10206 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10207 if (insn[0] == 0x0F && insn[1] == 0xC3) {
10208 vassert(sz == 4);
10209 modrm = getIByte(delta+2);
10210 if (!epartIsReg(modrm)) {
10211 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10212 storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
10213 DIP("movnti %s,%s\n", dis_buf,
10214 nameIReg(4, gregOfRM(modrm)));
10215 delta += 2+alen;
10216 goto decode_success;
10217 }
10218 /* else fall through */
10219 }
10220
sewardj95535fe2004-12-15 17:42:58 +000010221 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
10222 or lo half xmm). */
sewardj9ee82862004-12-14 01:16:59 +000010223 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
10224 modrm = getIByte(delta+2);
10225 if (epartIsReg(modrm)) {
10226 /* fall through, awaiting test case */
sewardj6d7ccd52005-05-14 02:04:12 +000010227 /* dst: lo half copied, hi half zeroed */
sewardj9ee82862004-12-14 01:16:59 +000010228 } else {
10229 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10230 storeLE( mkexpr(addr),
10231 getXMMRegLane64( gregOfRM(modrm), 0 ));
10232 DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
10233 delta += 2+alen;
10234 goto decode_success;
10235 }
10236 }
10237
sewardjc2feffc2004-12-08 12:31:22 +000010238 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10239 hi half). */
10240 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
10241 vassert(sz == 4);
10242 modrm = getIByte(delta+3);
10243 if (epartIsReg(modrm)) {
10244 do_MMX_preamble();
10245 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010246 unop(Iop_64UtoV128, getMMXReg( eregOfRM(modrm) )) );
sewardjc2feffc2004-12-08 12:31:22 +000010247 DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10248 nameXMMReg(gregOfRM(modrm)));
10249 delta += 3+1;
10250 goto decode_success;
10251 } else {
10252 /* fall through, apparently no mem case for this insn */
10253 }
10254 }
10255
sewardj95535fe2004-12-15 17:42:58 +000010256 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj6d7ccd52005-05-14 02:04:12 +000010257 G (lo half xmm). Upper half of G is zeroed out. */
sewardj95535fe2004-12-15 17:42:58 +000010258 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
10259 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj6d7ccd52005-05-14 02:04:12 +000010260 If E is reg, upper half of G is unchanged. */
sewardj95535fe2004-12-15 17:42:58 +000010261 if ((insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x10)
10262 || (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7E)) {
sewardjc2feffc2004-12-08 12:31:22 +000010263 vassert(sz == 4);
10264 modrm = getIByte(delta+3);
10265 if (epartIsReg(modrm)) {
10266 putXMMRegLane64( gregOfRM(modrm), 0,
10267 getXMMRegLane64( eregOfRM(modrm), 0 ));
sewardj6d7ccd52005-05-14 02:04:12 +000010268 if (insn[0] == 0xF3/*MOVQ*/) {
10269 /* zero bits 127:64 */
10270 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
10271 }
sewardjc2feffc2004-12-08 12:31:22 +000010272 DIP("movsd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10273 nameXMMReg(gregOfRM(modrm)));
10274 delta += 3+1;
10275 } else {
10276 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +000010277 /* zero bits 127:64 */
sewardj5bf1fd42005-04-06 01:11:08 +000010278 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
sewardjad50db02005-04-06 01:45:44 +000010279 /* write bits 63:0 */
sewardjc2feffc2004-12-08 12:31:22 +000010280 putXMMRegLane64( gregOfRM(modrm), 0,
10281 loadLE(Ity_I64, mkexpr(addr)) );
10282 DIP("movsd %s,%s\n", dis_buf,
10283 nameXMMReg(gregOfRM(modrm)));
10284 delta += 3+alen;
10285 }
10286 goto decode_success;
10287 }
10288
10289 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10290 or lo half xmm). */
10291 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x11) {
10292 vassert(sz == 4);
10293 modrm = getIByte(delta+3);
10294 if (epartIsReg(modrm)) {
sewardjb7ba04f2008-11-17 20:25:37 +000010295 putXMMRegLane64( eregOfRM(modrm), 0,
10296 getXMMRegLane64( gregOfRM(modrm), 0 ));
10297 DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
10298 nameXMMReg(eregOfRM(modrm)));
10299 delta += 3+1;
sewardjc2feffc2004-12-08 12:31:22 +000010300 } else {
10301 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10302 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +000010303 getXMMRegLane64(gregOfRM(modrm), 0) );
10304 DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardjc2feffc2004-12-08 12:31:22 +000010305 dis_buf);
10306 delta += 3+alen;
sewardjc2feffc2004-12-08 12:31:22 +000010307 }
sewardjb7ba04f2008-11-17 20:25:37 +000010308 goto decode_success;
sewardjc2feffc2004-12-08 12:31:22 +000010309 }
sewardjfd226452004-12-07 19:02:18 +000010310
sewardj008754b2004-12-08 14:37:10 +000010311 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10312 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
10313 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
10314 goto decode_success;
10315 }
10316
10317 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
10318 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
10319 vassert(sz == 4);
10320 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
10321 goto decode_success;
10322 }
10323
10324 /* 66 0F 56 = ORPD -- G = G and E */
10325 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +000010326 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_OrV128 );
sewardj008754b2004-12-08 14:37:10 +000010327 goto decode_success;
10328 }
10329
10330 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10331 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
10332 Int select;
10333 IRTemp sV = newTemp(Ity_V128);
10334 IRTemp dV = newTemp(Ity_V128);
10335 IRTemp s1 = newTemp(Ity_I64);
10336 IRTemp s0 = newTemp(Ity_I64);
10337 IRTemp d1 = newTemp(Ity_I64);
10338 IRTemp d0 = newTemp(Ity_I64);
10339
10340 modrm = insn[2];
10341 assign( dV, getXMMReg(gregOfRM(modrm)) );
10342
10343 if (epartIsReg(modrm)) {
10344 assign( sV, getXMMReg(eregOfRM(modrm)) );
10345 select = (Int)insn[3];
10346 delta += 2+2;
10347 DIP("shufpd $%d,%s,%s\n", select,
10348 nameXMMReg(eregOfRM(modrm)),
10349 nameXMMReg(gregOfRM(modrm)));
10350 } else {
10351 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10352 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10353 select = (Int)insn[2+alen];
10354 delta += 3+alen;
10355 DIP("shufpd $%d,%s,%s\n", select,
10356 dis_buf,
10357 nameXMMReg(gregOfRM(modrm)));
10358 }
10359
sewardjf0c1c582005-02-07 23:47:38 +000010360 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10361 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10362 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10363 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +000010364
10365# define SELD(n) mkexpr((n)==0 ? d0 : d1)
10366# define SELS(n) mkexpr((n)==0 ? s0 : s1)
10367
10368 putXMMReg(
10369 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010370 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
sewardj008754b2004-12-08 14:37:10 +000010371 );
10372
10373# undef SELD
10374# undef SELS
10375
10376 goto decode_success;
10377 }
10378
10379 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10380 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
10381 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
10382 "sqrtpd", Iop_Sqrt64Fx2 );
10383 goto decode_success;
10384 }
10385
10386 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10387 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
10388 vassert(sz == 4);
10389 delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3,
10390 "sqrtsd", Iop_Sqrt64F0x2 );
10391 goto decode_success;
10392 }
10393
10394 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10395 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
10396 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
10397 goto decode_success;
10398 }
10399
10400 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10401 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
10402 vassert(sz == 4);
10403 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
10404 goto decode_success;
10405 }
10406
10407 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10408 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10409 /* These just appear to be special cases of SHUFPS */
10410 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10411 IRTemp s1 = newTemp(Ity_I64);
10412 IRTemp s0 = newTemp(Ity_I64);
10413 IRTemp d1 = newTemp(Ity_I64);
10414 IRTemp d0 = newTemp(Ity_I64);
10415 IRTemp sV = newTemp(Ity_V128);
10416 IRTemp dV = newTemp(Ity_V128);
sewardj2d49b432005-02-01 00:37:06 +000010417 Bool hi = toBool(insn[1] == 0x15);
sewardj008754b2004-12-08 14:37:10 +000010418
10419 modrm = insn[2];
10420 assign( dV, getXMMReg(gregOfRM(modrm)) );
10421
10422 if (epartIsReg(modrm)) {
10423 assign( sV, getXMMReg(eregOfRM(modrm)) );
10424 delta += 2+1;
10425 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10426 nameXMMReg(eregOfRM(modrm)),
10427 nameXMMReg(gregOfRM(modrm)));
10428 } else {
10429 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10430 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10431 delta += 2+alen;
10432 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10433 dis_buf,
10434 nameXMMReg(gregOfRM(modrm)));
10435 }
10436
sewardjf0c1c582005-02-07 23:47:38 +000010437 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10438 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10439 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10440 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +000010441
10442 if (hi) {
10443 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010444 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
sewardj008754b2004-12-08 14:37:10 +000010445 } else {
10446 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010447 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
sewardj008754b2004-12-08 14:37:10 +000010448 }
10449
10450 goto decode_success;
10451 }
10452
10453 /* 66 0F 57 = XORPD -- G = G and E */
10454 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +000010455 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_XorV128 );
sewardj008754b2004-12-08 14:37:10 +000010456 goto decode_success;
10457 }
sewardj636ad762004-12-07 11:16:04 +000010458
sewardj164f9272004-12-09 00:39:32 +000010459 /* 66 0F 6B = PACKSSDW */
10460 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
10461 delta = dis_SSEint_E_to_G( sorb, delta+2,
10462 "packssdw", Iop_QNarrow32Sx4, True );
10463 goto decode_success;
10464 }
10465
10466 /* 66 0F 63 = PACKSSWB */
10467 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
10468 delta = dis_SSEint_E_to_G( sorb, delta+2,
10469 "packsswb", Iop_QNarrow16Sx8, True );
10470 goto decode_success;
10471 }
10472
10473 /* 66 0F 67 = PACKUSWB */
10474 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
10475 delta = dis_SSEint_E_to_G( sorb, delta+2,
10476 "packuswb", Iop_QNarrow16Ux8, True );
10477 goto decode_success;
10478 }
10479
10480 /* 66 0F FC = PADDB */
10481 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
10482 delta = dis_SSEint_E_to_G( sorb, delta+2,
10483 "paddb", Iop_Add8x16, False );
10484 goto decode_success;
10485 }
10486
10487 /* 66 0F FE = PADDD */
10488 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
10489 delta = dis_SSEint_E_to_G( sorb, delta+2,
10490 "paddd", Iop_Add32x4, False );
10491 goto decode_success;
10492 }
10493
10494 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10495 /* 0F D4 = PADDQ -- add 64x1 */
10496 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
10497 do_MMX_preamble();
10498 delta = dis_MMXop_regmem_to_reg (
10499 sorb, delta+2, insn[1], "paddq", False );
10500 goto decode_success;
10501 }
10502
10503 /* 66 0F D4 = PADDQ */
10504 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
10505 delta = dis_SSEint_E_to_G( sorb, delta+2,
10506 "paddq", Iop_Add64x2, False );
10507 goto decode_success;
10508 }
10509
10510 /* 66 0F FD = PADDW */
10511 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
10512 delta = dis_SSEint_E_to_G( sorb, delta+2,
10513 "paddw", Iop_Add16x8, False );
10514 goto decode_success;
10515 }
10516
10517 /* 66 0F EC = PADDSB */
10518 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
10519 delta = dis_SSEint_E_to_G( sorb, delta+2,
10520 "paddsb", Iop_QAdd8Sx16, False );
10521 goto decode_success;
10522 }
10523
10524 /* 66 0F ED = PADDSW */
10525 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
10526 delta = dis_SSEint_E_to_G( sorb, delta+2,
10527 "paddsw", Iop_QAdd16Sx8, False );
10528 goto decode_success;
10529 }
10530
10531 /* 66 0F DC = PADDUSB */
10532 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
10533 delta = dis_SSEint_E_to_G( sorb, delta+2,
10534 "paddusb", Iop_QAdd8Ux16, False );
10535 goto decode_success;
10536 }
10537
10538 /* 66 0F DD = PADDUSW */
10539 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
10540 delta = dis_SSEint_E_to_G( sorb, delta+2,
10541 "paddusw", Iop_QAdd16Ux8, False );
10542 goto decode_success;
10543 }
10544
10545 /* 66 0F DB = PAND */
10546 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
sewardjf0c1c582005-02-07 23:47:38 +000010547 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +000010548 goto decode_success;
10549 }
10550
10551 /* 66 0F DF = PANDN */
10552 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
sewardjf0c1c582005-02-07 23:47:38 +000010553 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +000010554 goto decode_success;
10555 }
10556
10557 /* 66 0F E0 = PAVGB */
10558 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
10559 delta = dis_SSEint_E_to_G( sorb, delta+2,
10560 "pavgb", Iop_Avg8Ux16, False );
10561 goto decode_success;
10562 }
10563
10564 /* 66 0F E3 = PAVGW */
10565 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
10566 delta = dis_SSEint_E_to_G( sorb, delta+2,
10567 "pavgw", Iop_Avg16Ux8, False );
10568 goto decode_success;
10569 }
10570
sewardje5854d62004-12-09 03:44:34 +000010571 /* 66 0F 74 = PCMPEQB */
10572 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
10573 delta = dis_SSEint_E_to_G( sorb, delta+2,
10574 "pcmpeqb", Iop_CmpEQ8x16, False );
10575 goto decode_success;
10576 }
10577
10578 /* 66 0F 76 = PCMPEQD */
10579 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
10580 delta = dis_SSEint_E_to_G( sorb, delta+2,
10581 "pcmpeqd", Iop_CmpEQ32x4, False );
10582 goto decode_success;
10583 }
10584
10585 /* 66 0F 75 = PCMPEQW */
10586 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
10587 delta = dis_SSEint_E_to_G( sorb, delta+2,
10588 "pcmpeqw", Iop_CmpEQ16x8, False );
10589 goto decode_success;
10590 }
10591
10592 /* 66 0F 64 = PCMPGTB */
10593 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
10594 delta = dis_SSEint_E_to_G( sorb, delta+2,
10595 "pcmpgtb", Iop_CmpGT8Sx16, False );
10596 goto decode_success;
10597 }
10598
10599 /* 66 0F 66 = PCMPGTD */
10600 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
10601 delta = dis_SSEint_E_to_G( sorb, delta+2,
10602 "pcmpgtd", Iop_CmpGT32Sx4, False );
10603 goto decode_success;
10604 }
10605
10606 /* 66 0F 65 = PCMPGTW */
10607 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
10608 delta = dis_SSEint_E_to_G( sorb, delta+2,
10609 "pcmpgtw", Iop_CmpGT16Sx8, False );
10610 goto decode_success;
10611 }
10612
10613 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10614 zero-extend of it in ireg(G). */
10615 if (insn[0] == 0x0F && insn[1] == 0xC5) {
10616 modrm = insn[2];
10617 if (sz == 2 && epartIsReg(modrm)) {
10618 t5 = newTemp(Ity_V128);
10619 t4 = newTemp(Ity_I16);
10620 assign(t5, getXMMReg(eregOfRM(modrm)));
10621 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10622 switch (insn[3] & 7) {
10623 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
10624 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
10625 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
10626 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
10627 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
10628 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
10629 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
10630 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
sewardjba89f4c2005-04-07 17:31:27 +000010631 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +000010632 }
10633 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
10634 DIP("pextrw $%d,%s,%s\n",
10635 (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
10636 nameIReg(4,gregOfRM(modrm)));
10637 delta += 4;
10638 goto decode_success;
10639 }
10640 /* else fall through */
10641 }
10642
10643 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
10644 put it into the specified lane of xmm(G). */
10645 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
10646 Int lane;
10647 t4 = newTemp(Ity_I16);
10648 modrm = insn[2];
10649
10650 if (epartIsReg(modrm)) {
10651 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +000010652 delta += 3+1;
10653 lane = insn[3+1-1];
sewardje5854d62004-12-09 03:44:34 +000010654 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10655 nameIReg(2,eregOfRM(modrm)),
10656 nameXMMReg(gregOfRM(modrm)));
10657 } else {
sewardjaac7e082005-03-17 14:03:46 +000010658 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10659 delta += 3+alen;
10660 lane = insn[3+alen-1];
10661 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
10662 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10663 dis_buf,
10664 nameXMMReg(gregOfRM(modrm)));
sewardje5854d62004-12-09 03:44:34 +000010665 }
10666
10667 putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
10668 goto decode_success;
10669 }
10670
sewardjb8a3dea2005-10-04 20:00:49 +000010671 /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
10672 E(xmm or mem) to G(xmm) */
10673 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF5) {
10674 IRTemp s1V = newTemp(Ity_V128);
10675 IRTemp s2V = newTemp(Ity_V128);
10676 IRTemp dV = newTemp(Ity_V128);
10677 IRTemp s1Hi = newTemp(Ity_I64);
10678 IRTemp s1Lo = newTemp(Ity_I64);
10679 IRTemp s2Hi = newTemp(Ity_I64);
10680 IRTemp s2Lo = newTemp(Ity_I64);
10681 IRTemp dHi = newTemp(Ity_I64);
10682 IRTemp dLo = newTemp(Ity_I64);
10683 modrm = insn[2];
10684 if (epartIsReg(modrm)) {
10685 assign( s1V, getXMMReg(eregOfRM(modrm)) );
10686 delta += 2+1;
10687 DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10688 nameXMMReg(gregOfRM(modrm)));
10689 } else {
10690 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10691 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
10692 delta += 2+alen;
10693 DIP("pmaddwd %s,%s\n", dis_buf,
10694 nameXMMReg(gregOfRM(modrm)));
10695 }
10696 assign( s2V, getXMMReg(gregOfRM(modrm)) );
10697 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
10698 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
10699 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
10700 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
10701 assign( dHi, mkIRExprCCall(
10702 Ity_I64, 0/*regparms*/,
10703 "x86g_calculate_mmx_pmaddwd",
10704 &x86g_calculate_mmx_pmaddwd,
10705 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
10706 ));
10707 assign( dLo, mkIRExprCCall(
10708 Ity_I64, 0/*regparms*/,
10709 "x86g_calculate_mmx_pmaddwd",
10710 &x86g_calculate_mmx_pmaddwd,
10711 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
10712 ));
10713 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
10714 putXMMReg(gregOfRM(modrm), mkexpr(dV));
10715 goto decode_success;
10716 }
10717
sewardje5854d62004-12-09 03:44:34 +000010718 /* 66 0F EE = PMAXSW -- 16x8 signed max */
10719 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
10720 delta = dis_SSEint_E_to_G( sorb, delta+2,
10721 "pmaxsw", Iop_Max16Sx8, False );
10722 goto decode_success;
10723 }
10724
10725 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
10726 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
10727 delta = dis_SSEint_E_to_G( sorb, delta+2,
10728 "pmaxub", Iop_Max8Ux16, False );
10729 goto decode_success;
10730 }
10731
10732 /* 66 0F EA = PMINSW -- 16x8 signed min */
10733 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
10734 delta = dis_SSEint_E_to_G( sorb, delta+2,
10735 "pminsw", Iop_Min16Sx8, False );
10736 goto decode_success;
10737 }
10738
10739 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
10740 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
10741 delta = dis_SSEint_E_to_G( sorb, delta+2,
10742 "pminub", Iop_Min8Ux16, False );
10743 goto decode_success;
10744 }
10745
10746 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
10747 xmm(G), turn them into a byte, and put zero-extend of it in
10748 ireg(G). Doing this directly is just too cumbersome; give up
10749 therefore and call a helper. */
10750 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
10751 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
10752 modrm = insn[2];
10753 if (epartIsReg(modrm)) {
10754 t0 = newTemp(Ity_I64);
10755 t1 = newTemp(Ity_I64);
10756 assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
10757 assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
10758 t5 = newTemp(Ity_I32);
10759 assign(t5, mkIRExprCCall(
10760 Ity_I32, 0/*regparms*/,
10761 "x86g_calculate_sse_pmovmskb",
10762 &x86g_calculate_sse_pmovmskb,
sewardj28e5c832004-12-16 11:39:04 +000010763 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
sewardje5854d62004-12-09 03:44:34 +000010764 putIReg(4, gregOfRM(modrm), mkexpr(t5));
10765 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10766 nameIReg(4,gregOfRM(modrm)));
10767 delta += 3;
10768 goto decode_success;
10769 }
10770 /* else fall through */
10771 }
10772
10773 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
10774 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
10775 delta = dis_SSEint_E_to_G( sorb, delta+2,
10776 "pmulhuw", Iop_MulHi16Ux8, False );
10777 goto decode_success;
10778 }
10779
10780 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
10781 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
10782 delta = dis_SSEint_E_to_G( sorb, delta+2,
10783 "pmulhw", Iop_MulHi16Sx8, False );
10784 goto decode_success;
10785 }
10786
10787 /* 66 0F D5 = PMULHL -- 16x8 multiply */
10788 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
10789 delta = dis_SSEint_E_to_G( sorb, delta+2,
10790 "pmullw", Iop_Mul16x8, False );
10791 goto decode_success;
10792 }
10793
10794 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10795 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10796 0 to form 64-bit result */
10797 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
10798 IRTemp sV = newTemp(Ity_I64);
10799 IRTemp dV = newTemp(Ity_I64);
10800 t1 = newTemp(Ity_I32);
10801 t0 = newTemp(Ity_I32);
10802 modrm = insn[2];
10803
10804 do_MMX_preamble();
10805 assign( dV, getMMXReg(gregOfRM(modrm)) );
10806
10807 if (epartIsReg(modrm)) {
10808 assign( sV, getMMXReg(eregOfRM(modrm)) );
10809 delta += 2+1;
10810 DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10811 nameMMXReg(gregOfRM(modrm)));
10812 } else {
10813 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10814 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
10815 delta += 2+alen;
10816 DIP("pmuludq %s,%s\n", dis_buf,
10817 nameMMXReg(gregOfRM(modrm)));
10818 }
10819
10820 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
10821 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
10822 putMMXReg( gregOfRM(modrm),
10823 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
10824 goto decode_success;
10825 }
10826
10827 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10828 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
10829 half */
10830 /* This is a really poor translation -- could be improved if
10831 performance critical */
10832 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
10833 IRTemp sV, dV;
10834 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
10835 sV = newTemp(Ity_V128);
10836 dV = newTemp(Ity_V128);
10837 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
10838 t1 = newTemp(Ity_I64);
10839 t0 = newTemp(Ity_I64);
10840 modrm = insn[2];
10841 assign( dV, getXMMReg(gregOfRM(modrm)) );
10842
10843 if (epartIsReg(modrm)) {
10844 assign( sV, getXMMReg(eregOfRM(modrm)) );
10845 delta += 2+1;
10846 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10847 nameXMMReg(gregOfRM(modrm)));
10848 } else {
10849 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10850 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10851 delta += 2+alen;
10852 DIP("pmuludq %s,%s\n", dis_buf,
10853 nameXMMReg(gregOfRM(modrm)));
10854 }
10855
10856 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
10857 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10858
10859 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
10860 putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
10861 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
10862 putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
10863 goto decode_success;
10864 }
10865
10866 /* 66 0F EB = POR */
10867 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
sewardjf0c1c582005-02-07 23:47:38 +000010868 delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_OrV128 );
sewardje5854d62004-12-09 03:44:34 +000010869 goto decode_success;
10870 }
10871
sewardj7b5b9982005-10-04 11:43:37 +000010872 /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
10873 from E(xmm or mem) to G(xmm) */
10874 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF6) {
10875 IRTemp s1V = newTemp(Ity_V128);
10876 IRTemp s2V = newTemp(Ity_V128);
10877 IRTemp dV = newTemp(Ity_V128);
10878 IRTemp s1Hi = newTemp(Ity_I64);
10879 IRTemp s1Lo = newTemp(Ity_I64);
10880 IRTemp s2Hi = newTemp(Ity_I64);
10881 IRTemp s2Lo = newTemp(Ity_I64);
10882 IRTemp dHi = newTemp(Ity_I64);
10883 IRTemp dLo = newTemp(Ity_I64);
10884 modrm = insn[2];
10885 if (epartIsReg(modrm)) {
10886 assign( s1V, getXMMReg(eregOfRM(modrm)) );
10887 delta += 2+1;
10888 DIP("psadbw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10889 nameXMMReg(gregOfRM(modrm)));
10890 } else {
10891 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10892 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
10893 delta += 2+alen;
10894 DIP("psadbw %s,%s\n", dis_buf,
10895 nameXMMReg(gregOfRM(modrm)));
10896 }
10897 assign( s2V, getXMMReg(gregOfRM(modrm)) );
10898 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
10899 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
10900 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
10901 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
10902 assign( dHi, mkIRExprCCall(
10903 Ity_I64, 0/*regparms*/,
10904 "x86g_calculate_mmx_psadbw",
10905 &x86g_calculate_mmx_psadbw,
10906 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
10907 ));
10908 assign( dLo, mkIRExprCCall(
10909 Ity_I64, 0/*regparms*/,
10910 "x86g_calculate_mmx_psadbw",
10911 &x86g_calculate_mmx_psadbw,
10912 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
10913 ));
10914 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
10915 putXMMReg(gregOfRM(modrm), mkexpr(dV));
10916 goto decode_success;
10917 }
10918
sewardjb9fa69b2004-12-09 23:25:14 +000010919 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
10920 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
10921 Int order;
10922 IRTemp sV, dV, s3, s2, s1, s0;
10923 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10924 sV = newTemp(Ity_V128);
10925 dV = newTemp(Ity_V128);
10926 modrm = insn[2];
10927 if (epartIsReg(modrm)) {
10928 assign( sV, getXMMReg(eregOfRM(modrm)) );
10929 order = (Int)insn[3];
10930 delta += 2+2;
10931 DIP("pshufd $%d,%s,%s\n", order,
10932 nameXMMReg(eregOfRM(modrm)),
10933 nameXMMReg(gregOfRM(modrm)));
10934 } else {
10935 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10936 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10937 order = (Int)insn[2+alen];
10938 delta += 3+alen;
10939 DIP("pshufd $%d,%s,%s\n", order,
10940 dis_buf,
10941 nameXMMReg(gregOfRM(modrm)));
10942 }
10943 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10944
10945# define SEL(n) \
10946 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10947 assign(dV,
10948 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
10949 SEL((order>>2)&3), SEL((order>>0)&3) )
10950 );
10951 putXMMReg(gregOfRM(modrm), mkexpr(dV));
10952# undef SEL
10953 goto decode_success;
10954 }
10955
10956 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
10957 mem) to G(xmm), and copy lower half */
10958 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
10959 Int order;
10960 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
10961 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10962 sV = newTemp(Ity_V128);
10963 dV = newTemp(Ity_V128);
10964 sVhi = newTemp(Ity_I64);
10965 dVhi = newTemp(Ity_I64);
10966 modrm = insn[3];
10967 if (epartIsReg(modrm)) {
10968 assign( sV, getXMMReg(eregOfRM(modrm)) );
10969 order = (Int)insn[4];
10970 delta += 4+1;
10971 DIP("pshufhw $%d,%s,%s\n", order,
10972 nameXMMReg(eregOfRM(modrm)),
10973 nameXMMReg(gregOfRM(modrm)));
10974 } else {
10975 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10976 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10977 order = (Int)insn[3+alen];
10978 delta += 4+alen;
10979 DIP("pshufhw $%d,%s,%s\n", order,
10980 dis_buf,
10981 nameXMMReg(gregOfRM(modrm)));
10982 }
sewardjf0c1c582005-02-07 23:47:38 +000010983 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +000010984 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
10985
10986# define SEL(n) \
10987 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10988 assign(dVhi,
10989 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
10990 SEL((order>>2)&3), SEL((order>>0)&3) )
10991 );
sewardjf0c1c582005-02-07 23:47:38 +000010992 assign(dV, binop( Iop_64HLtoV128,
sewardjb9fa69b2004-12-09 23:25:14 +000010993 mkexpr(dVhi),
sewardjf0c1c582005-02-07 23:47:38 +000010994 unop(Iop_V128to64, mkexpr(sV))) );
sewardjb9fa69b2004-12-09 23:25:14 +000010995 putXMMReg(gregOfRM(modrm), mkexpr(dV));
10996# undef SEL
10997 goto decode_success;
10998 }
10999
11000 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
11001 mem) to G(xmm), and copy upper half */
11002 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
11003 Int order;
11004 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
11005 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11006 sV = newTemp(Ity_V128);
11007 dV = newTemp(Ity_V128);
11008 sVlo = newTemp(Ity_I64);
11009 dVlo = newTemp(Ity_I64);
11010 modrm = insn[3];
11011 if (epartIsReg(modrm)) {
11012 assign( sV, getXMMReg(eregOfRM(modrm)) );
11013 order = (Int)insn[4];
11014 delta += 4+1;
11015 DIP("pshuflw $%d,%s,%s\n", order,
11016 nameXMMReg(eregOfRM(modrm)),
11017 nameXMMReg(gregOfRM(modrm)));
11018 } else {
11019 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11020 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11021 order = (Int)insn[3+alen];
11022 delta += 4+alen;
11023 DIP("pshuflw $%d,%s,%s\n", order,
11024 dis_buf,
11025 nameXMMReg(gregOfRM(modrm)));
11026 }
sewardjf0c1c582005-02-07 23:47:38 +000011027 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +000011028 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
11029
11030# define SEL(n) \
11031 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11032 assign(dVlo,
11033 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11034 SEL((order>>2)&3), SEL((order>>0)&3) )
11035 );
sewardjf0c1c582005-02-07 23:47:38 +000011036 assign(dV, binop( Iop_64HLtoV128,
11037 unop(Iop_V128HIto64, mkexpr(sV)),
sewardjb9fa69b2004-12-09 23:25:14 +000011038 mkexpr(dVlo) ) );
11039 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11040# undef SEL
11041 goto decode_success;
11042 }
11043
11044 /* 66 0F 72 /6 ib = PSLLD by immediate */
11045 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11046 && epartIsReg(insn[2])
11047 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000011048 delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000011049 goto decode_success;
11050 }
11051
11052 /* 66 0F F2 = PSLLD by E */
11053 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
11054 delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
11055 goto decode_success;
11056 }
11057
sewardjb9fa69b2004-12-09 23:25:14 +000011058 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
11059 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11060 && epartIsReg(insn[2])
11061 && gregOfRM(insn[2]) == 7) {
sewardj0c9907c2005-01-10 20:37:31 +000011062 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11063 Int imm = (Int)insn[3];
11064 Int reg = eregOfRM(insn[2]);
11065 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
11066 vassert(imm >= 0 && imm <= 255);
11067 delta += 4;
11068
11069 sV = newTemp(Ity_V128);
11070 dV = newTemp(Ity_V128);
11071 hi64 = newTemp(Ity_I64);
11072 lo64 = newTemp(Ity_I64);
11073 hi64r = newTemp(Ity_I64);
11074 lo64r = newTemp(Ity_I64);
11075
11076 if (imm >= 16) {
sewardj0c9907c2005-01-10 20:37:31 +000011077 putXMMReg(reg, mkV128(0x0000));
11078 goto decode_success;
11079 }
11080
11081 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +000011082 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11083 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj0c9907c2005-01-10 20:37:31 +000011084
sewardjba89f4c2005-04-07 17:31:27 +000011085 if (imm == 0) {
11086 assign( lo64r, mkexpr(lo64) );
11087 assign( hi64r, mkexpr(hi64) );
11088 }
11089 else
sewardj0c9907c2005-01-10 20:37:31 +000011090 if (imm == 8) {
11091 assign( lo64r, mkU64(0) );
11092 assign( hi64r, mkexpr(lo64) );
11093 }
sewardjc02043c2005-01-11 15:03:53 +000011094 else
sewardj0c9907c2005-01-10 20:37:31 +000011095 if (imm > 8) {
sewardj0c9907c2005-01-10 20:37:31 +000011096 assign( lo64r, mkU64(0) );
11097 assign( hi64r, binop( Iop_Shl64,
11098 mkexpr(lo64),
11099 mkU8( 8*(imm-8) ) ));
11100 } else {
11101 assign( lo64r, binop( Iop_Shl64,
11102 mkexpr(lo64),
11103 mkU8(8 * imm) ));
11104 assign( hi64r,
11105 binop( Iop_Or64,
11106 binop(Iop_Shl64, mkexpr(hi64),
11107 mkU8(8 * imm)),
11108 binop(Iop_Shr64, mkexpr(lo64),
11109 mkU8(8 * (8 - imm)) )
11110 )
11111 );
11112 }
sewardjf0c1c582005-02-07 23:47:38 +000011113 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj0c9907c2005-01-10 20:37:31 +000011114 putXMMReg(reg, mkexpr(dV));
sewardjb9fa69b2004-12-09 23:25:14 +000011115 goto decode_success;
11116 }
sewardjb9fa69b2004-12-09 23:25:14 +000011117
11118 /* 66 0F 73 /6 ib = PSLLQ by immediate */
11119 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11120 && epartIsReg(insn[2])
11121 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000011122 delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +000011123 goto decode_success;
11124 }
11125
11126 /* 66 0F F3 = PSLLQ by E */
11127 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
11128 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
11129 goto decode_success;
11130 }
11131
11132 /* 66 0F 71 /6 ib = PSLLW by immediate */
11133 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11134 && epartIsReg(insn[2])
11135 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000011136 delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000011137 goto decode_success;
11138 }
11139
11140 /* 66 0F F1 = PSLLW by E */
11141 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
11142 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
11143 goto decode_success;
11144 }
11145
11146 /* 66 0F 72 /4 ib = PSRAD by immediate */
11147 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11148 && epartIsReg(insn[2])
11149 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +000011150 delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000011151 goto decode_success;
11152 }
11153
11154 /* 66 0F E2 = PSRAD by E */
11155 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
11156 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
11157 goto decode_success;
11158 }
11159
11160 /* 66 0F 71 /4 ib = PSRAW by immediate */
11161 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11162 && epartIsReg(insn[2])
11163 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +000011164 delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000011165 goto decode_success;
11166 }
11167
11168 /* 66 0F E1 = PSRAW by E */
11169 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
11170 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
11171 goto decode_success;
11172 }
11173
11174 /* 66 0F 72 /2 ib = PSRLD by immediate */
11175 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11176 && epartIsReg(insn[2])
11177 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000011178 delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000011179 goto decode_success;
11180 }
11181
11182 /* 66 0F D2 = PSRLD by E */
11183 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
11184 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
11185 goto decode_success;
11186 }
11187
sewardj9ee82862004-12-14 01:16:59 +000011188 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
11189 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11190 && epartIsReg(insn[2])
sewardj95535fe2004-12-15 17:42:58 +000011191 && gregOfRM(insn[2]) == 3) {
11192 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
sewardj9ee82862004-12-14 01:16:59 +000011193 Int imm = (Int)insn[3];
11194 Int reg = eregOfRM(insn[2]);
sewardj9ee82862004-12-14 01:16:59 +000011195 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
sewardj95535fe2004-12-15 17:42:58 +000011196 vassert(imm >= 0 && imm <= 255);
11197 delta += 4;
11198
11199 sV = newTemp(Ity_V128);
11200 dV = newTemp(Ity_V128);
11201 hi64 = newTemp(Ity_I64);
11202 lo64 = newTemp(Ity_I64);
11203 hi64r = newTemp(Ity_I64);
11204 lo64r = newTemp(Ity_I64);
11205
11206 if (imm >= 16) {
sewardj95535fe2004-12-15 17:42:58 +000011207 putXMMReg(reg, mkV128(0x0000));
11208 goto decode_success;
11209 }
11210
11211 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +000011212 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11213 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj95535fe2004-12-15 17:42:58 +000011214
sewardjba89f4c2005-04-07 17:31:27 +000011215 if (imm == 0) {
11216 assign( lo64r, mkexpr(lo64) );
11217 assign( hi64r, mkexpr(hi64) );
11218 }
11219 else
sewardj95535fe2004-12-15 17:42:58 +000011220 if (imm == 8) {
11221 assign( hi64r, mkU64(0) );
11222 assign( lo64r, mkexpr(hi64) );
11223 }
11224 else
11225 if (imm > 8) {
sewardj95535fe2004-12-15 17:42:58 +000011226 assign( hi64r, mkU64(0) );
11227 assign( lo64r, binop( Iop_Shr64,
11228 mkexpr(hi64),
11229 mkU8( 8*(imm-8) ) ));
11230 } else {
11231 assign( hi64r, binop( Iop_Shr64,
11232 mkexpr(hi64),
11233 mkU8(8 * imm) ));
11234 assign( lo64r,
11235 binop( Iop_Or64,
11236 binop(Iop_Shr64, mkexpr(lo64),
11237 mkU8(8 * imm)),
11238 binop(Iop_Shl64, mkexpr(hi64),
11239 mkU8(8 * (8 - imm)) )
11240 )
11241 );
11242 }
11243
sewardjf0c1c582005-02-07 23:47:38 +000011244 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj95535fe2004-12-15 17:42:58 +000011245 putXMMReg(reg, mkexpr(dV));
sewardj9ee82862004-12-14 01:16:59 +000011246 goto decode_success;
11247 }
11248
sewardjb9fa69b2004-12-09 23:25:14 +000011249 /* 66 0F 73 /2 ib = PSRLQ by immediate */
11250 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11251 && epartIsReg(insn[2])
11252 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000011253 delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +000011254 goto decode_success;
11255 }
11256
11257 /* 66 0F D3 = PSRLQ by E */
11258 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
11259 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
11260 goto decode_success;
11261 }
11262
11263 /* 66 0F 71 /2 ib = PSRLW by immediate */
11264 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11265 && epartIsReg(insn[2])
11266 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000011267 delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000011268 goto decode_success;
11269 }
11270
11271 /* 66 0F D1 = PSRLW by E */
11272 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
11273 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
11274 goto decode_success;
11275 }
11276
11277 /* 66 0F F8 = PSUBB */
11278 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
11279 delta = dis_SSEint_E_to_G( sorb, delta+2,
11280 "psubb", Iop_Sub8x16, False );
11281 goto decode_success;
11282 }
11283
11284 /* 66 0F FA = PSUBD */
11285 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
11286 delta = dis_SSEint_E_to_G( sorb, delta+2,
11287 "psubd", Iop_Sub32x4, False );
11288 goto decode_success;
11289 }
11290
11291 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11292 /* 0F FB = PSUBQ -- sub 64x1 */
11293 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
11294 do_MMX_preamble();
11295 delta = dis_MMXop_regmem_to_reg (
11296 sorb, delta+2, insn[1], "psubq", False );
11297 goto decode_success;
11298 }
11299
11300 /* 66 0F FB = PSUBQ */
11301 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
11302 delta = dis_SSEint_E_to_G( sorb, delta+2,
11303 "psubq", Iop_Sub64x2, False );
11304 goto decode_success;
11305 }
11306
11307 /* 66 0F F9 = PSUBW */
11308 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
11309 delta = dis_SSEint_E_to_G( sorb, delta+2,
11310 "psubw", Iop_Sub16x8, False );
11311 goto decode_success;
11312 }
11313
11314 /* 66 0F E8 = PSUBSB */
11315 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
11316 delta = dis_SSEint_E_to_G( sorb, delta+2,
11317 "psubsb", Iop_QSub8Sx16, False );
11318 goto decode_success;
11319 }
11320
11321 /* 66 0F E9 = PSUBSW */
11322 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
11323 delta = dis_SSEint_E_to_G( sorb, delta+2,
11324 "psubsw", Iop_QSub16Sx8, False );
11325 goto decode_success;
11326 }
11327
11328 /* 66 0F D8 = PSUBSB */
11329 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
11330 delta = dis_SSEint_E_to_G( sorb, delta+2,
11331 "psubusb", Iop_QSub8Ux16, False );
11332 goto decode_success;
11333 }
11334
11335 /* 66 0F D9 = PSUBSW */
11336 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
11337 delta = dis_SSEint_E_to_G( sorb, delta+2,
11338 "psubusw", Iop_QSub16Ux8, False );
11339 goto decode_success;
11340 }
11341
sewardj9e203592004-12-10 01:48:18 +000011342 /* 66 0F 68 = PUNPCKHBW */
11343 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
11344 delta = dis_SSEint_E_to_G( sorb, delta+2,
11345 "punpckhbw",
11346 Iop_InterleaveHI8x16, True );
11347 goto decode_success;
11348 }
11349
11350 /* 66 0F 6A = PUNPCKHDQ */
11351 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
11352 delta = dis_SSEint_E_to_G( sorb, delta+2,
11353 "punpckhdq",
11354 Iop_InterleaveHI32x4, True );
11355 goto decode_success;
11356 }
11357
11358 /* 66 0F 6D = PUNPCKHQDQ */
11359 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
11360 delta = dis_SSEint_E_to_G( sorb, delta+2,
11361 "punpckhqdq",
11362 Iop_InterleaveHI64x2, True );
11363 goto decode_success;
11364 }
11365
11366 /* 66 0F 69 = PUNPCKHWD */
11367 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
11368 delta = dis_SSEint_E_to_G( sorb, delta+2,
11369 "punpckhwd",
11370 Iop_InterleaveHI16x8, True );
11371 goto decode_success;
11372 }
11373
11374 /* 66 0F 60 = PUNPCKLBW */
11375 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
11376 delta = dis_SSEint_E_to_G( sorb, delta+2,
11377 "punpcklbw",
11378 Iop_InterleaveLO8x16, True );
11379 goto decode_success;
11380 }
11381
11382 /* 66 0F 62 = PUNPCKLDQ */
11383 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
11384 delta = dis_SSEint_E_to_G( sorb, delta+2,
11385 "punpckldq",
11386 Iop_InterleaveLO32x4, True );
11387 goto decode_success;
11388 }
11389
11390 /* 66 0F 6C = PUNPCKLQDQ */
11391 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
11392 delta = dis_SSEint_E_to_G( sorb, delta+2,
11393 "punpcklqdq",
11394 Iop_InterleaveLO64x2, True );
11395 goto decode_success;
11396 }
11397
11398 /* 66 0F 61 = PUNPCKLWD */
11399 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
11400 delta = dis_SSEint_E_to_G( sorb, delta+2,
11401 "punpcklwd",
11402 Iop_InterleaveLO16x8, True );
11403 goto decode_success;
11404 }
11405
11406 /* 66 0F EF = PXOR */
11407 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
sewardjf0c1c582005-02-07 23:47:38 +000011408 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_XorV128 );
sewardj9e203592004-12-10 01:48:18 +000011409 goto decode_success;
11410 }
11411
sewardjc9a65702004-07-07 16:32:57 +000011412//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11413//-- if (insn[0] == 0x0F && insn[1] == 0xAE
11414//-- && (!epartIsReg(insn[2]))
11415//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11416//-- Bool store = gregOfRM(insn[2]) == 0;
11417//-- vg_assert(sz == 4);
11418//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11419//-- t1 = LOW24(pair);
11420//-- eip += 2+HI8(pair);
11421//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11422//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11423//-- Lit16, (UShort)insn[2],
11424//-- TempReg, t1 );
11425//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11426//-- goto decode_success;
11427//-- }
sewardjc9a65702004-07-07 16:32:57 +000011428
sewardjbfceb082005-11-15 11:16:30 +000011429 /* 0F AE /7 = CLFLUSH -- flush cache line */
11430 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
11431 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
11432
11433 /* This is something of a hack. We need to know the size of the
11434 cache line containing addr. Since we don't (easily), assume
11435 256 on the basis that no real cache would have a line that
11436 big. It's safe to invalidate more stuff than we need, just
11437 inefficient. */
11438 UInt lineszB = 256;
11439
11440 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11441 delta += 2+alen;
11442
11443 /* Round addr down to the start of the containing block. */
11444 stmt( IRStmt_Put(
11445 OFFB_TISTART,
11446 binop( Iop_And32,
11447 mkexpr(addr),
11448 mkU32( ~(lineszB-1) ))) );
11449
11450 stmt( IRStmt_Put(OFFB_TILEN, mkU32(lineszB) ) );
11451
sewardjdd40fdf2006-12-24 02:20:24 +000011452 irsb->jumpkind = Ijk_TInval;
11453 irsb->next = mkU32(guest_EIP_bbstart+delta);
sewardjbfceb082005-11-15 11:16:30 +000011454 dres.whatNext = Dis_StopHere;
11455
11456 DIP("clflush %s\n", dis_buf);
11457 goto decode_success;
11458 }
sewardjc9a65702004-07-07 16:32:57 +000011459
11460 /* ---------------------------------------------------- */
sewardj90e91ee2005-11-07 14:23:52 +000011461 /* --- end of the SSE2 decoder. --- */
11462 /* ---------------------------------------------------- */
11463
11464 /* ---------------------------------------------------- */
11465 /* --- start of the SSE3 decoder. --- */
11466 /* ---------------------------------------------------- */
11467
11468 /* Skip parts of the decoder which don't apply given the stated
11469 guest subarchitecture. */
sewardj5117ce12006-01-27 21:20:15 +000011470 /* if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE3)) */
11471 /* In fact this is highly bogus; we accept SSE3 insns even on a
11472 SSE2-only guest since they turn into IR which can be re-emitted
11473 successfully on an SSE2 host. */
11474 if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
11475 goto after_sse_decoders; /* no SSE3 capabilities */
sewardj90e91ee2005-11-07 14:23:52 +000011476
11477 insn = (UChar*)&guest_code[delta];
11478
11479 /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
11480 duplicating some lanes (2:2:0:0). */
11481 /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
11482 duplicating some lanes (3:3:1:1). */
11483 if (sz == 4 && insn[0] == 0xF3 && insn[1] == 0x0F
11484 && (insn[2] == 0x12 || insn[2] == 0x16)) {
11485 IRTemp s3, s2, s1, s0;
11486 IRTemp sV = newTemp(Ity_V128);
11487 Bool isH = insn[2] == 0x16;
11488 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11489
11490 modrm = insn[3];
11491 if (epartIsReg(modrm)) {
11492 assign( sV, getXMMReg( eregOfRM(modrm)) );
11493 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11494 nameXMMReg(eregOfRM(modrm)),
11495 nameXMMReg(gregOfRM(modrm)));
11496 delta += 3+1;
11497 } else {
11498 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11499 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11500 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11501 dis_buf,
11502 nameXMMReg(gregOfRM(modrm)));
11503 delta += 3+alen;
11504 }
11505
11506 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11507 putXMMReg( gregOfRM(modrm),
11508 isH ? mk128from32s( s3, s3, s1, s1 )
11509 : mk128from32s( s2, s2, s0, s0 ) );
11510 goto decode_success;
11511 }
11512
sewardjdd5d2042006-08-03 15:03:19 +000011513 /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
11514 duplicating some lanes (0:1:0:1). */
11515 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x12) {
11516 IRTemp sV = newTemp(Ity_V128);
11517 IRTemp d0 = newTemp(Ity_I64);
11518
11519 modrm = insn[3];
11520 if (epartIsReg(modrm)) {
11521 assign( sV, getXMMReg( eregOfRM(modrm)) );
11522 DIP("movddup %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11523 nameXMMReg(gregOfRM(modrm)));
11524 delta += 3+1;
11525 assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
11526 } else {
11527 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11528 assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
11529 DIP("movddup %s,%s\n", dis_buf,
11530 nameXMMReg(gregOfRM(modrm)));
11531 delta += 3+alen;
11532 }
11533
11534 putXMMReg( gregOfRM(modrm), binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
11535 goto decode_success;
11536 }
11537
sewardj90e91ee2005-11-07 14:23:52 +000011538 /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
11539 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD0) {
11540 IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
11541 IRTemp eV = newTemp(Ity_V128);
11542 IRTemp gV = newTemp(Ity_V128);
11543 IRTemp addV = newTemp(Ity_V128);
11544 IRTemp subV = newTemp(Ity_V128);
11545 a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
11546
11547 modrm = insn[3];
11548 if (epartIsReg(modrm)) {
11549 assign( eV, getXMMReg( eregOfRM(modrm)) );
11550 DIP("addsubps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11551 nameXMMReg(gregOfRM(modrm)));
11552 delta += 3+1;
11553 } else {
11554 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11555 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11556 DIP("addsubps %s,%s\n", dis_buf,
11557 nameXMMReg(gregOfRM(modrm)));
11558 delta += 3+alen;
11559 }
11560
11561 assign( gV, getXMMReg(gregOfRM(modrm)) );
11562
11563 assign( addV, binop(Iop_Add32Fx4, mkexpr(gV), mkexpr(eV)) );
11564 assign( subV, binop(Iop_Sub32Fx4, mkexpr(gV), mkexpr(eV)) );
11565
11566 breakup128to32s( addV, &a3, &a2, &a1, &a0 );
11567 breakup128to32s( subV, &s3, &s2, &s1, &s0 );
11568
11569 putXMMReg( gregOfRM(modrm), mk128from32s( a3, s2, a1, s0 ));
11570 goto decode_success;
11571 }
11572
sewardjdd5d2042006-08-03 15:03:19 +000011573 /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
11574 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD0) {
11575 IRTemp eV = newTemp(Ity_V128);
11576 IRTemp gV = newTemp(Ity_V128);
11577 IRTemp addV = newTemp(Ity_V128);
11578 IRTemp subV = newTemp(Ity_V128);
11579 IRTemp a1 = newTemp(Ity_I64);
11580 IRTemp s0 = newTemp(Ity_I64);
11581
11582 modrm = insn[2];
11583 if (epartIsReg(modrm)) {
11584 assign( eV, getXMMReg( eregOfRM(modrm)) );
11585 DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11586 nameXMMReg(gregOfRM(modrm)));
11587 delta += 2+1;
11588 } else {
11589 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11590 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11591 DIP("addsubpd %s,%s\n", dis_buf,
11592 nameXMMReg(gregOfRM(modrm)));
11593 delta += 2+alen;
11594 }
11595
11596 assign( gV, getXMMReg(gregOfRM(modrm)) );
11597
11598 assign( addV, binop(Iop_Add64Fx2, mkexpr(gV), mkexpr(eV)) );
11599 assign( subV, binop(Iop_Sub64Fx2, mkexpr(gV), mkexpr(eV)) );
11600
11601 assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
11602 assign( s0, unop(Iop_V128to64, mkexpr(subV) ));
11603
11604 putXMMReg( gregOfRM(modrm),
11605 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
11606 goto decode_success;
11607 }
11608
11609 /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
11610 /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
11611 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F
11612 && (insn[2] == 0x7C || insn[2] == 0x7D)) {
11613 IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
11614 IRTemp eV = newTemp(Ity_V128);
11615 IRTemp gV = newTemp(Ity_V128);
11616 IRTemp leftV = newTemp(Ity_V128);
11617 IRTemp rightV = newTemp(Ity_V128);
11618 Bool isAdd = insn[2] == 0x7C;
11619 HChar* str = isAdd ? "add" : "sub";
11620 e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
11621
11622 modrm = insn[3];
11623 if (epartIsReg(modrm)) {
11624 assign( eV, getXMMReg( eregOfRM(modrm)) );
11625 DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11626 nameXMMReg(gregOfRM(modrm)));
11627 delta += 3+1;
11628 } else {
11629 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11630 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11631 DIP("h%sps %s,%s\n", str, dis_buf,
11632 nameXMMReg(gregOfRM(modrm)));
11633 delta += 3+alen;
11634 }
11635
11636 assign( gV, getXMMReg(gregOfRM(modrm)) );
11637
11638 breakup128to32s( eV, &e3, &e2, &e1, &e0 );
11639 breakup128to32s( gV, &g3, &g2, &g1, &g0 );
11640
11641 assign( leftV, mk128from32s( e2, e0, g2, g0 ) );
11642 assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
11643
11644 putXMMReg( gregOfRM(modrm),
11645 binop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
11646 mkexpr(leftV), mkexpr(rightV) ) );
11647 goto decode_success;
11648 }
11649
11650 /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
11651 /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
11652 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
11653 IRTemp e1 = newTemp(Ity_I64);
11654 IRTemp e0 = newTemp(Ity_I64);
11655 IRTemp g1 = newTemp(Ity_I64);
11656 IRTemp g0 = newTemp(Ity_I64);
11657 IRTemp eV = newTemp(Ity_V128);
11658 IRTemp gV = newTemp(Ity_V128);
11659 IRTemp leftV = newTemp(Ity_V128);
11660 IRTemp rightV = newTemp(Ity_V128);
11661 Bool isAdd = insn[1] == 0x7C;
11662 HChar* str = isAdd ? "add" : "sub";
11663
11664 modrm = insn[2];
11665 if (epartIsReg(modrm)) {
11666 assign( eV, getXMMReg( eregOfRM(modrm)) );
11667 DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11668 nameXMMReg(gregOfRM(modrm)));
11669 delta += 2+1;
11670 } else {
11671 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11672 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11673 DIP("h%spd %s,%s\n", str, dis_buf,
11674 nameXMMReg(gregOfRM(modrm)));
11675 delta += 2+alen;
11676 }
11677
11678 assign( gV, getXMMReg(gregOfRM(modrm)) );
11679
11680 assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
11681 assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
11682 assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
11683 assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
11684
11685 assign( leftV, binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
11686 assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
11687
11688 putXMMReg( gregOfRM(modrm),
11689 binop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
11690 mkexpr(leftV), mkexpr(rightV) ) );
11691 goto decode_success;
11692 }
11693
11694 /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
11695 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xF0) {
11696 modrm = getIByte(delta+3);
11697 if (epartIsReg(modrm)) {
11698 goto decode_failure;
11699 } else {
11700 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11701 putXMMReg( gregOfRM(modrm),
11702 loadLE(Ity_V128, mkexpr(addr)) );
11703 DIP("lddqu %s,%s\n", dis_buf,
11704 nameXMMReg(gregOfRM(modrm)));
11705 delta += 3+alen;
11706 }
11707 goto decode_success;
11708 }
11709
sewardj90e91ee2005-11-07 14:23:52 +000011710 /* ---------------------------------------------------- */
11711 /* --- end of the SSE3 decoder. --- */
sewardjc9a65702004-07-07 16:32:57 +000011712 /* ---------------------------------------------------- */
11713
sewardj150c9cd2008-02-09 01:16:02 +000011714 /* ---------------------------------------------------- */
11715 /* --- start of the SSSE3 decoder. --- */
11716 /* ---------------------------------------------------- */
11717
11718 /* 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
11719 Unsigned Bytes (MMX) */
11720 if (sz == 4
11721 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
11722 IRTemp sV = newTemp(Ity_I64);
11723 IRTemp dV = newTemp(Ity_I64);
11724 IRTemp sVoddsSX = newTemp(Ity_I64);
11725 IRTemp sVevensSX = newTemp(Ity_I64);
11726 IRTemp dVoddsZX = newTemp(Ity_I64);
11727 IRTemp dVevensZX = newTemp(Ity_I64);
11728
11729 modrm = insn[3];
11730 do_MMX_preamble();
11731 assign( dV, getMMXReg(gregOfRM(modrm)) );
11732
11733 if (epartIsReg(modrm)) {
11734 assign( sV, getMMXReg(eregOfRM(modrm)) );
11735 delta += 3+1;
11736 DIP("pmaddubsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
11737 nameMMXReg(gregOfRM(modrm)));
11738 } else {
11739 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11740 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11741 delta += 3+alen;
11742 DIP("pmaddubsw %s,%s\n", dis_buf,
11743 nameMMXReg(gregOfRM(modrm)));
11744 }
11745
11746 /* compute dV unsigned x sV signed */
11747 assign( sVoddsSX,
11748 binop(Iop_SarN16x4, mkexpr(sV), mkU8(8)) );
11749 assign( sVevensSX,
11750 binop(Iop_SarN16x4,
11751 binop(Iop_ShlN16x4, mkexpr(sV), mkU8(8)),
11752 mkU8(8)) );
11753 assign( dVoddsZX,
11754 binop(Iop_ShrN16x4, mkexpr(dV), mkU8(8)) );
11755 assign( dVevensZX,
11756 binop(Iop_ShrN16x4,
11757 binop(Iop_ShlN16x4, mkexpr(dV), mkU8(8)),
11758 mkU8(8)) );
11759
11760 putMMXReg(
11761 gregOfRM(modrm),
11762 binop(Iop_QAdd16Sx4,
11763 binop(Iop_Mul16x4, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
11764 binop(Iop_Mul16x4, mkexpr(sVevensSX), mkexpr(dVevensZX))
11765 )
11766 );
11767 goto decode_success;
11768 }
11769
11770 /* 66 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
11771 Unsigned Bytes (XMM) */
11772 if (sz == 2
11773 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
11774 IRTemp sV = newTemp(Ity_V128);
11775 IRTemp dV = newTemp(Ity_V128);
11776 IRTemp sVoddsSX = newTemp(Ity_V128);
11777 IRTemp sVevensSX = newTemp(Ity_V128);
11778 IRTemp dVoddsZX = newTemp(Ity_V128);
11779 IRTemp dVevensZX = newTemp(Ity_V128);
11780
11781 modrm = insn[3];
11782 assign( dV, getXMMReg(gregOfRM(modrm)) );
11783
11784 if (epartIsReg(modrm)) {
11785 assign( sV, getXMMReg(eregOfRM(modrm)) );
11786 delta += 3+1;
11787 DIP("pmaddubsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11788 nameXMMReg(gregOfRM(modrm)));
11789 } else {
11790 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11791 gen_SEGV_if_not_16_aligned( addr );
11792 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11793 delta += 3+alen;
11794 DIP("pmaddubsw %s,%s\n", dis_buf,
11795 nameXMMReg(gregOfRM(modrm)));
11796 }
11797
11798 /* compute dV unsigned x sV signed */
11799 assign( sVoddsSX,
11800 binop(Iop_SarN16x8, mkexpr(sV), mkU8(8)) );
11801 assign( sVevensSX,
11802 binop(Iop_SarN16x8,
11803 binop(Iop_ShlN16x8, mkexpr(sV), mkU8(8)),
11804 mkU8(8)) );
11805 assign( dVoddsZX,
11806 binop(Iop_ShrN16x8, mkexpr(dV), mkU8(8)) );
11807 assign( dVevensZX,
11808 binop(Iop_ShrN16x8,
11809 binop(Iop_ShlN16x8, mkexpr(dV), mkU8(8)),
11810 mkU8(8)) );
11811
11812 putXMMReg(
11813 gregOfRM(modrm),
11814 binop(Iop_QAdd16Sx8,
11815 binop(Iop_Mul16x8, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
11816 binop(Iop_Mul16x8, mkexpr(sVevensSX), mkexpr(dVevensZX))
11817 )
11818 );
11819 goto decode_success;
11820 }
11821
11822 /* ***--- these are MMX class insns introduced in SSSE3 ---*** */
11823 /* 0F 38 03 = PHADDSW -- 16x4 signed qadd across from E (mem or
11824 mmx) and G to G (mmx). */
11825 /* 0F 38 07 = PHSUBSW -- 16x4 signed qsub across from E (mem or
11826 mmx) and G to G (mmx). */
11827 /* 0F 38 01 = PHADDW -- 16x4 add across from E (mem or mmx) and G
11828 to G (mmx). */
11829 /* 0F 38 05 = PHSUBW -- 16x4 sub across from E (mem or mmx) and G
11830 to G (mmx). */
11831 /* 0F 38 02 = PHADDD -- 32x2 add across from E (mem or mmx) and G
11832 to G (mmx). */
11833 /* 0F 38 06 = PHSUBD -- 32x2 sub across from E (mem or mmx) and G
11834 to G (mmx). */
11835
11836 if (sz == 4
11837 && insn[0] == 0x0F && insn[1] == 0x38
11838 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
11839 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
11840 HChar* str = "???";
11841 IROp opV64 = Iop_INVALID;
11842 IROp opCatO = Iop_CatOddLanes16x4;
11843 IROp opCatE = Iop_CatEvenLanes16x4;
11844 IRTemp sV = newTemp(Ity_I64);
11845 IRTemp dV = newTemp(Ity_I64);
11846
11847 modrm = insn[3];
11848
11849 switch (insn[2]) {
11850 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
11851 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
11852 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
11853 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
11854 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
11855 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
11856 default: vassert(0);
11857 }
11858 if (insn[2] == 0x02 || insn[2] == 0x06) {
11859 opCatO = Iop_InterleaveHI32x2;
11860 opCatE = Iop_InterleaveLO32x2;
11861 }
11862
11863 do_MMX_preamble();
11864 assign( dV, getMMXReg(gregOfRM(modrm)) );
11865
11866 if (epartIsReg(modrm)) {
11867 assign( sV, getMMXReg(eregOfRM(modrm)) );
11868 delta += 3+1;
11869 DIP("ph%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
11870 nameMMXReg(gregOfRM(modrm)));
11871 } else {
11872 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11873 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11874 delta += 3+alen;
11875 DIP("ph%s %s,%s\n", str, dis_buf,
11876 nameMMXReg(gregOfRM(modrm)));
11877 }
11878
11879 putMMXReg(
11880 gregOfRM(modrm),
11881 binop(opV64,
11882 binop(opCatE,mkexpr(sV),mkexpr(dV)),
11883 binop(opCatO,mkexpr(sV),mkexpr(dV))
11884 )
11885 );
11886 goto decode_success;
11887 }
11888
11889 /* 66 0F 38 03 = PHADDSW -- 16x8 signed qadd across from E (mem or
11890 xmm) and G to G (xmm). */
11891 /* 66 0F 38 07 = PHSUBSW -- 16x8 signed qsub across from E (mem or
11892 xmm) and G to G (xmm). */
11893 /* 66 0F 38 01 = PHADDW -- 16x8 add across from E (mem or xmm) and
11894 G to G (xmm). */
11895 /* 66 0F 38 05 = PHSUBW -- 16x8 sub across from E (mem or xmm) and
11896 G to G (xmm). */
11897 /* 66 0F 38 02 = PHADDD -- 32x4 add across from E (mem or xmm) and
11898 G to G (xmm). */
11899 /* 66 0F 38 06 = PHSUBD -- 32x4 sub across from E (mem or xmm) and
11900 G to G (xmm). */
11901
11902 if (sz == 2
11903 && insn[0] == 0x0F && insn[1] == 0x38
11904 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
11905 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
11906 HChar* str = "???";
11907 IROp opV64 = Iop_INVALID;
11908 IROp opCatO = Iop_CatOddLanes16x4;
11909 IROp opCatE = Iop_CatEvenLanes16x4;
11910 IRTemp sV = newTemp(Ity_V128);
11911 IRTemp dV = newTemp(Ity_V128);
11912 IRTemp sHi = newTemp(Ity_I64);
11913 IRTemp sLo = newTemp(Ity_I64);
11914 IRTemp dHi = newTemp(Ity_I64);
11915 IRTemp dLo = newTemp(Ity_I64);
11916
11917 modrm = insn[3];
11918
11919 switch (insn[2]) {
11920 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
11921 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
11922 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
11923 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
11924 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
11925 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
11926 default: vassert(0);
11927 }
11928 if (insn[2] == 0x02 || insn[2] == 0x06) {
11929 opCatO = Iop_InterleaveHI32x2;
11930 opCatE = Iop_InterleaveLO32x2;
11931 }
11932
11933 assign( dV, getXMMReg(gregOfRM(modrm)) );
11934
11935 if (epartIsReg(modrm)) {
11936 assign( sV, getXMMReg( eregOfRM(modrm)) );
11937 DIP("ph%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11938 nameXMMReg(gregOfRM(modrm)));
11939 delta += 3+1;
11940 } else {
11941 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11942 gen_SEGV_if_not_16_aligned( addr );
11943 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11944 DIP("ph%s %s,%s\n", str, dis_buf,
11945 nameXMMReg(gregOfRM(modrm)));
11946 delta += 3+alen;
11947 }
11948
11949 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
11950 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
11951 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
11952 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
11953
11954 /* This isn't a particularly efficient way to compute the
11955 result, but at least it avoids a proliferation of IROps,
11956 hence avoids complication all the backends. */
11957 putXMMReg(
11958 gregOfRM(modrm),
11959 binop(Iop_64HLtoV128,
11960 binop(opV64,
11961 binop(opCatE,mkexpr(sHi),mkexpr(sLo)),
11962 binop(opCatO,mkexpr(sHi),mkexpr(sLo))
11963 ),
11964 binop(opV64,
11965 binop(opCatE,mkexpr(dHi),mkexpr(dLo)),
11966 binop(opCatO,mkexpr(dHi),mkexpr(dLo))
11967 )
11968 )
11969 );
11970 goto decode_success;
11971 }
11972
11973 /* 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and Scale
11974 (MMX) */
11975 if (sz == 4
11976 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
11977 IRTemp sV = newTemp(Ity_I64);
11978 IRTemp dV = newTemp(Ity_I64);
11979
11980 modrm = insn[3];
11981 do_MMX_preamble();
11982 assign( dV, getMMXReg(gregOfRM(modrm)) );
11983
11984 if (epartIsReg(modrm)) {
11985 assign( sV, getMMXReg(eregOfRM(modrm)) );
11986 delta += 3+1;
11987 DIP("pmulhrsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
11988 nameMMXReg(gregOfRM(modrm)));
11989 } else {
11990 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11991 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11992 delta += 3+alen;
11993 DIP("pmulhrsw %s,%s\n", dis_buf,
11994 nameMMXReg(gregOfRM(modrm)));
11995 }
11996
11997 putMMXReg(
11998 gregOfRM(modrm),
11999 dis_PMULHRSW_helper( mkexpr(sV), mkexpr(dV) )
12000 );
12001 goto decode_success;
12002 }
12003
12004 /* 66 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and
12005 Scale (XMM) */
12006 if (sz == 2
12007 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12008 IRTemp sV = newTemp(Ity_V128);
12009 IRTemp dV = newTemp(Ity_V128);
12010 IRTemp sHi = newTemp(Ity_I64);
12011 IRTemp sLo = newTemp(Ity_I64);
12012 IRTemp dHi = newTemp(Ity_I64);
12013 IRTemp dLo = newTemp(Ity_I64);
12014
12015 modrm = insn[3];
12016 assign( dV, getXMMReg(gregOfRM(modrm)) );
12017
12018 if (epartIsReg(modrm)) {
12019 assign( sV, getXMMReg(eregOfRM(modrm)) );
12020 delta += 3+1;
12021 DIP("pmulhrsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12022 nameXMMReg(gregOfRM(modrm)));
12023 } else {
12024 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12025 gen_SEGV_if_not_16_aligned( addr );
12026 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12027 delta += 3+alen;
12028 DIP("pmulhrsw %s,%s\n", dis_buf,
12029 nameXMMReg(gregOfRM(modrm)));
12030 }
12031
12032 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12033 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12034 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12035 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12036
12037 putXMMReg(
12038 gregOfRM(modrm),
12039 binop(Iop_64HLtoV128,
12040 dis_PMULHRSW_helper( mkexpr(sHi), mkexpr(dHi) ),
12041 dis_PMULHRSW_helper( mkexpr(sLo), mkexpr(dLo) )
12042 )
12043 );
12044 goto decode_success;
12045 }
12046
12047 /* 0F 38 08 = PSIGNB -- Packed Sign 8x8 (MMX) */
12048 /* 0F 38 09 = PSIGNW -- Packed Sign 16x4 (MMX) */
12049 /* 0F 38 09 = PSIGND -- Packed Sign 32x2 (MMX) */
12050 if (sz == 4
12051 && insn[0] == 0x0F && insn[1] == 0x38
12052 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12053 IRTemp sV = newTemp(Ity_I64);
12054 IRTemp dV = newTemp(Ity_I64);
12055 HChar* str = "???";
12056 Int laneszB = 0;
12057
12058 switch (insn[2]) {
12059 case 0x08: laneszB = 1; str = "b"; break;
12060 case 0x09: laneszB = 2; str = "w"; break;
12061 case 0x0A: laneszB = 4; str = "d"; break;
12062 default: vassert(0);
12063 }
12064
12065 modrm = insn[3];
12066 do_MMX_preamble();
12067 assign( dV, getMMXReg(gregOfRM(modrm)) );
12068
12069 if (epartIsReg(modrm)) {
12070 assign( sV, getMMXReg(eregOfRM(modrm)) );
12071 delta += 3+1;
12072 DIP("psign%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12073 nameMMXReg(gregOfRM(modrm)));
12074 } else {
12075 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12076 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12077 delta += 3+alen;
12078 DIP("psign%s %s,%s\n", str, dis_buf,
12079 nameMMXReg(gregOfRM(modrm)));
12080 }
12081
12082 putMMXReg(
12083 gregOfRM(modrm),
12084 dis_PSIGN_helper( mkexpr(sV), mkexpr(dV), laneszB )
12085 );
12086 goto decode_success;
12087 }
12088
12089 /* 66 0F 38 08 = PSIGNB -- Packed Sign 8x16 (XMM) */
12090 /* 66 0F 38 09 = PSIGNW -- Packed Sign 16x8 (XMM) */
12091 /* 66 0F 38 09 = PSIGND -- Packed Sign 32x4 (XMM) */
12092 if (sz == 2
12093 && insn[0] == 0x0F && insn[1] == 0x38
12094 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12095 IRTemp sV = newTemp(Ity_V128);
12096 IRTemp dV = newTemp(Ity_V128);
12097 IRTemp sHi = newTemp(Ity_I64);
12098 IRTemp sLo = newTemp(Ity_I64);
12099 IRTemp dHi = newTemp(Ity_I64);
12100 IRTemp dLo = newTemp(Ity_I64);
12101 HChar* str = "???";
12102 Int laneszB = 0;
12103
12104 switch (insn[2]) {
12105 case 0x08: laneszB = 1; str = "b"; break;
12106 case 0x09: laneszB = 2; str = "w"; break;
12107 case 0x0A: laneszB = 4; str = "d"; break;
12108 default: vassert(0);
12109 }
12110
12111 modrm = insn[3];
12112 assign( dV, getXMMReg(gregOfRM(modrm)) );
12113
12114 if (epartIsReg(modrm)) {
12115 assign( sV, getXMMReg(eregOfRM(modrm)) );
12116 delta += 3+1;
12117 DIP("psign%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12118 nameXMMReg(gregOfRM(modrm)));
12119 } else {
12120 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12121 gen_SEGV_if_not_16_aligned( addr );
12122 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12123 delta += 3+alen;
12124 DIP("psign%s %s,%s\n", str, dis_buf,
12125 nameXMMReg(gregOfRM(modrm)));
12126 }
12127
12128 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12129 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12130 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12131 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12132
12133 putXMMReg(
12134 gregOfRM(modrm),
12135 binop(Iop_64HLtoV128,
12136 dis_PSIGN_helper( mkexpr(sHi), mkexpr(dHi), laneszB ),
12137 dis_PSIGN_helper( mkexpr(sLo), mkexpr(dLo), laneszB )
12138 )
12139 );
12140 goto decode_success;
12141 }
12142
12143 /* 0F 38 1C = PABSB -- Packed Absolute Value 8x8 (MMX) */
12144 /* 0F 38 1D = PABSW -- Packed Absolute Value 16x4 (MMX) */
12145 /* 0F 38 1E = PABSD -- Packed Absolute Value 32x2 (MMX) */
12146 if (sz == 4
12147 && insn[0] == 0x0F && insn[1] == 0x38
12148 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12149 IRTemp sV = newTemp(Ity_I64);
12150 HChar* str = "???";
12151 Int laneszB = 0;
12152
12153 switch (insn[2]) {
12154 case 0x1C: laneszB = 1; str = "b"; break;
12155 case 0x1D: laneszB = 2; str = "w"; break;
12156 case 0x1E: laneszB = 4; str = "d"; break;
12157 default: vassert(0);
12158 }
12159
12160 modrm = insn[3];
12161 do_MMX_preamble();
12162
12163 if (epartIsReg(modrm)) {
12164 assign( sV, getMMXReg(eregOfRM(modrm)) );
12165 delta += 3+1;
12166 DIP("pabs%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12167 nameMMXReg(gregOfRM(modrm)));
12168 } else {
12169 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12170 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12171 delta += 3+alen;
12172 DIP("pabs%s %s,%s\n", str, dis_buf,
12173 nameMMXReg(gregOfRM(modrm)));
12174 }
12175
12176 putMMXReg(
12177 gregOfRM(modrm),
12178 dis_PABS_helper( mkexpr(sV), laneszB )
12179 );
12180 goto decode_success;
12181 }
12182
12183 /* 66 0F 38 1C = PABSB -- Packed Absolute Value 8x16 (XMM) */
12184 /* 66 0F 38 1D = PABSW -- Packed Absolute Value 16x8 (XMM) */
12185 /* 66 0F 38 1E = PABSD -- Packed Absolute Value 32x4 (XMM) */
12186 if (sz == 2
12187 && insn[0] == 0x0F && insn[1] == 0x38
12188 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12189 IRTemp sV = newTemp(Ity_V128);
12190 IRTemp sHi = newTemp(Ity_I64);
12191 IRTemp sLo = newTemp(Ity_I64);
12192 HChar* str = "???";
12193 Int laneszB = 0;
12194
12195 switch (insn[2]) {
12196 case 0x1C: laneszB = 1; str = "b"; break;
12197 case 0x1D: laneszB = 2; str = "w"; break;
12198 case 0x1E: laneszB = 4; str = "d"; break;
12199 default: vassert(0);
12200 }
12201
12202 modrm = insn[3];
12203
12204 if (epartIsReg(modrm)) {
12205 assign( sV, getXMMReg(eregOfRM(modrm)) );
12206 delta += 3+1;
12207 DIP("pabs%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12208 nameXMMReg(gregOfRM(modrm)));
12209 } else {
12210 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12211 gen_SEGV_if_not_16_aligned( addr );
12212 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12213 delta += 3+alen;
12214 DIP("pabs%s %s,%s\n", str, dis_buf,
12215 nameXMMReg(gregOfRM(modrm)));
12216 }
12217
12218 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12219 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12220
12221 putXMMReg(
12222 gregOfRM(modrm),
12223 binop(Iop_64HLtoV128,
12224 dis_PABS_helper( mkexpr(sHi), laneszB ),
12225 dis_PABS_helper( mkexpr(sLo), laneszB )
12226 )
12227 );
12228 goto decode_success;
12229 }
12230
12231 /* 0F 3A 0F = PALIGNR -- Packed Align Right (MMX) */
12232 if (sz == 4
12233 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12234 IRTemp sV = newTemp(Ity_I64);
12235 IRTemp dV = newTemp(Ity_I64);
12236 IRTemp res = newTemp(Ity_I64);
12237
12238 modrm = insn[3];
12239 do_MMX_preamble();
12240 assign( dV, getMMXReg(gregOfRM(modrm)) );
12241
12242 if (epartIsReg(modrm)) {
12243 assign( sV, getMMXReg(eregOfRM(modrm)) );
12244 d32 = (UInt)insn[3+1];
12245 delta += 3+1+1;
12246 DIP("palignr $%d,%s,%s\n", (Int)d32,
12247 nameMMXReg(eregOfRM(modrm)),
12248 nameMMXReg(gregOfRM(modrm)));
12249 } else {
12250 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12251 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12252 d32 = (UInt)insn[3+alen];
12253 delta += 3+alen+1;
12254 DIP("palignr $%d%s,%s\n", (Int)d32,
12255 dis_buf,
12256 nameMMXReg(gregOfRM(modrm)));
12257 }
12258
12259 if (d32 == 0) {
12260 assign( res, mkexpr(sV) );
12261 }
12262 else if (d32 >= 1 && d32 <= 7) {
12263 assign(res,
12264 binop(Iop_Or64,
12265 binop(Iop_Shr64, mkexpr(sV), mkU8(8*d32)),
12266 binop(Iop_Shl64, mkexpr(dV), mkU8(8*(8-d32))
12267 )));
12268 }
12269 else if (d32 == 8) {
12270 assign( res, mkexpr(dV) );
12271 }
12272 else if (d32 >= 9 && d32 <= 15) {
12273 assign( res, binop(Iop_Shr64, mkexpr(dV), mkU8(8*(d32-8))) );
12274 }
12275 else if (d32 >= 16 && d32 <= 255) {
12276 assign( res, mkU64(0) );
12277 }
12278 else
12279 vassert(0);
12280
12281 putMMXReg( gregOfRM(modrm), mkexpr(res) );
12282 goto decode_success;
12283 }
12284
12285 /* 66 0F 3A 0F = PALIGNR -- Packed Align Right (XMM) */
12286 if (sz == 2
12287 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12288 IRTemp sV = newTemp(Ity_V128);
12289 IRTemp dV = newTemp(Ity_V128);
12290 IRTemp sHi = newTemp(Ity_I64);
12291 IRTemp sLo = newTemp(Ity_I64);
12292 IRTemp dHi = newTemp(Ity_I64);
12293 IRTemp dLo = newTemp(Ity_I64);
12294 IRTemp rHi = newTemp(Ity_I64);
12295 IRTemp rLo = newTemp(Ity_I64);
12296
12297 modrm = insn[3];
12298 assign( dV, getXMMReg(gregOfRM(modrm)) );
12299
12300 if (epartIsReg(modrm)) {
12301 assign( sV, getXMMReg(eregOfRM(modrm)) );
12302 d32 = (UInt)insn[3+1];
12303 delta += 3+1+1;
12304 DIP("palignr $%d,%s,%s\n", (Int)d32,
12305 nameXMMReg(eregOfRM(modrm)),
12306 nameXMMReg(gregOfRM(modrm)));
12307 } else {
12308 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12309 gen_SEGV_if_not_16_aligned( addr );
12310 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12311 d32 = (UInt)insn[3+alen];
12312 delta += 3+alen+1;
12313 DIP("palignr $%d,%s,%s\n", (Int)d32,
12314 dis_buf,
12315 nameXMMReg(gregOfRM(modrm)));
12316 }
12317
12318 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12319 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12320 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12321 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12322
12323 if (d32 == 0) {
12324 assign( rHi, mkexpr(sHi) );
12325 assign( rLo, mkexpr(sLo) );
12326 }
12327 else if (d32 >= 1 && d32 <= 7) {
12328 assign( rHi, dis_PALIGNR_XMM_helper(dLo, sHi, d32) );
12329 assign( rLo, dis_PALIGNR_XMM_helper(sHi, sLo, d32) );
12330 }
12331 else if (d32 == 8) {
12332 assign( rHi, mkexpr(dLo) );
12333 assign( rLo, mkexpr(sHi) );
12334 }
12335 else if (d32 >= 9 && d32 <= 15) {
12336 assign( rHi, dis_PALIGNR_XMM_helper(dHi, dLo, d32-8) );
12337 assign( rLo, dis_PALIGNR_XMM_helper(dLo, sHi, d32-8) );
12338 }
12339 else if (d32 == 16) {
12340 assign( rHi, mkexpr(dHi) );
12341 assign( rLo, mkexpr(dLo) );
12342 }
12343 else if (d32 >= 17 && d32 <= 23) {
12344 assign( rHi, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-16))) );
12345 assign( rLo, dis_PALIGNR_XMM_helper(dHi, dLo, d32-16) );
12346 }
12347 else if (d32 == 24) {
12348 assign( rHi, mkU64(0) );
12349 assign( rLo, mkexpr(dHi) );
12350 }
12351 else if (d32 >= 25 && d32 <= 31) {
12352 assign( rHi, mkU64(0) );
12353 assign( rLo, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-24))) );
12354 }
12355 else if (d32 >= 32 && d32 <= 255) {
12356 assign( rHi, mkU64(0) );
12357 assign( rLo, mkU64(0) );
12358 }
12359 else
12360 vassert(0);
12361
12362 putXMMReg(
12363 gregOfRM(modrm),
12364 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12365 );
12366 goto decode_success;
12367 }
12368
12369 /* 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x8 (MMX) */
12370 if (sz == 4
12371 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12372 IRTemp sV = newTemp(Ity_I64);
12373 IRTemp dV = newTemp(Ity_I64);
12374
12375 modrm = insn[3];
12376 do_MMX_preamble();
12377 assign( dV, getMMXReg(gregOfRM(modrm)) );
12378
12379 if (epartIsReg(modrm)) {
12380 assign( sV, getMMXReg(eregOfRM(modrm)) );
12381 delta += 3+1;
12382 DIP("pshufb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12383 nameMMXReg(gregOfRM(modrm)));
12384 } else {
12385 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12386 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12387 delta += 3+alen;
12388 DIP("pshufb %s,%s\n", dis_buf,
12389 nameMMXReg(gregOfRM(modrm)));
12390 }
12391
12392 putMMXReg(
12393 gregOfRM(modrm),
12394 binop(
12395 Iop_And64,
12396 /* permute the lanes */
12397 binop(
12398 Iop_Perm8x8,
12399 mkexpr(dV),
12400 binop(Iop_And64, mkexpr(sV), mkU64(0x0707070707070707ULL))
12401 ),
12402 /* mask off lanes which have (index & 0x80) == 0x80 */
12403 unop(Iop_Not64, binop(Iop_SarN8x8, mkexpr(sV), mkU8(7)))
12404 )
12405 );
12406 goto decode_success;
12407 }
12408
12409 /* 66 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x16 (XMM) */
12410 if (sz == 2
12411 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12412 IRTemp sV = newTemp(Ity_V128);
12413 IRTemp dV = newTemp(Ity_V128);
12414 IRTemp sHi = newTemp(Ity_I64);
12415 IRTemp sLo = newTemp(Ity_I64);
12416 IRTemp dHi = newTemp(Ity_I64);
12417 IRTemp dLo = newTemp(Ity_I64);
12418 IRTemp rHi = newTemp(Ity_I64);
12419 IRTemp rLo = newTemp(Ity_I64);
12420 IRTemp sevens = newTemp(Ity_I64);
12421 IRTemp mask0x80hi = newTemp(Ity_I64);
12422 IRTemp mask0x80lo = newTemp(Ity_I64);
12423 IRTemp maskBit3hi = newTemp(Ity_I64);
12424 IRTemp maskBit3lo = newTemp(Ity_I64);
12425 IRTemp sAnd7hi = newTemp(Ity_I64);
12426 IRTemp sAnd7lo = newTemp(Ity_I64);
12427 IRTemp permdHi = newTemp(Ity_I64);
12428 IRTemp permdLo = newTemp(Ity_I64);
12429
12430 modrm = insn[3];
12431 assign( dV, getXMMReg(gregOfRM(modrm)) );
12432
12433 if (epartIsReg(modrm)) {
12434 assign( sV, getXMMReg(eregOfRM(modrm)) );
12435 delta += 3+1;
12436 DIP("pshufb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12437 nameXMMReg(gregOfRM(modrm)));
12438 } else {
12439 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12440 gen_SEGV_if_not_16_aligned( addr );
12441 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12442 delta += 3+alen;
12443 DIP("pshufb %s,%s\n", dis_buf,
12444 nameXMMReg(gregOfRM(modrm)));
12445 }
12446
12447 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12448 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12449 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12450 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12451
12452 assign( sevens, mkU64(0x0707070707070707ULL) );
12453
12454 /*
12455 mask0x80hi = Not(SarN8x8(sHi,7))
12456 maskBit3hi = SarN8x8(ShlN8x8(sHi,4),7)
12457 sAnd7hi = And(sHi,sevens)
12458 permdHi = Or( And(Perm8x8(dHi,sAnd7hi),maskBit3hi),
12459 And(Perm8x8(dLo,sAnd7hi),Not(maskBit3hi)) )
12460 rHi = And(permdHi,mask0x80hi)
12461 */
12462 assign(
12463 mask0x80hi,
12464 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sHi),mkU8(7))));
12465
12466 assign(
12467 maskBit3hi,
12468 binop(Iop_SarN8x8,
12469 binop(Iop_ShlN8x8,mkexpr(sHi),mkU8(4)),
12470 mkU8(7)));
12471
12472 assign(sAnd7hi, binop(Iop_And64,mkexpr(sHi),mkexpr(sevens)));
12473
12474 assign(
12475 permdHi,
12476 binop(
12477 Iop_Or64,
12478 binop(Iop_And64,
12479 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7hi)),
12480 mkexpr(maskBit3hi)),
12481 binop(Iop_And64,
12482 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7hi)),
12483 unop(Iop_Not64,mkexpr(maskBit3hi))) ));
12484
12485 assign(rHi, binop(Iop_And64,mkexpr(permdHi),mkexpr(mask0x80hi)) );
12486
12487 /* And the same for the lower half of the result. What fun. */
12488
12489 assign(
12490 mask0x80lo,
12491 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sLo),mkU8(7))));
12492
12493 assign(
12494 maskBit3lo,
12495 binop(Iop_SarN8x8,
12496 binop(Iop_ShlN8x8,mkexpr(sLo),mkU8(4)),
12497 mkU8(7)));
12498
12499 assign(sAnd7lo, binop(Iop_And64,mkexpr(sLo),mkexpr(sevens)));
12500
12501 assign(
12502 permdLo,
12503 binop(
12504 Iop_Or64,
12505 binop(Iop_And64,
12506 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7lo)),
12507 mkexpr(maskBit3lo)),
12508 binop(Iop_And64,
12509 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7lo)),
12510 unop(Iop_Not64,mkexpr(maskBit3lo))) ));
12511
12512 assign(rLo, binop(Iop_And64,mkexpr(permdLo),mkexpr(mask0x80lo)) );
12513
12514 putXMMReg(
12515 gregOfRM(modrm),
12516 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12517 );
12518 goto decode_success;
12519 }
12520
12521 /* ---------------------------------------------------- */
12522 /* --- end of the SSSE3 decoder. --- */
12523 /* ---------------------------------------------------- */
12524
sewardjb7271612010-07-23 21:23:25 +000012525 /* ---------------------------------------------------- */
12526 /* --- start of the SSE4 decoder --- */
12527 /* ---------------------------------------------------- */
12528
12529 /* 66 0F 3A 0B /r ib = ROUNDSD imm8, xmm2/m64, xmm1
12530 (Partial implementation only -- only deal with cases where
12531 the rounding mode is specified directly by the immediate byte.)
12532 66 0F 3A 0A /r ib = ROUNDSS imm8, xmm2/m32, xmm1
12533 (Limitations ditto)
12534 */
12535 if (sz == 2
12536 && insn[0] == 0x0F && insn[1] == 0x3A
12537 && (/*insn[2] == 0x0B || */insn[2] == 0x0A)) {
12538
12539 Bool isD = insn[2] == 0x0B;
12540 IRTemp src = newTemp(isD ? Ity_F64 : Ity_F32);
12541 IRTemp res = newTemp(isD ? Ity_F64 : Ity_F32);
12542 Int imm = 0;
12543
12544 modrm = insn[3];
12545
12546 if (epartIsReg(modrm)) {
12547 assign( src,
12548 isD ? getXMMRegLane64F( eregOfRM(modrm), 0 )
12549 : getXMMRegLane32F( eregOfRM(modrm), 0 ) );
12550 imm = insn[3+1];
12551 if (imm & ~3) goto decode_failure;
12552 delta += 3+1+1;
12553 DIP( "rounds%c $%d,%s,%s\n",
12554 isD ? 'd' : 's',
12555 imm, nameXMMReg( eregOfRM(modrm) ),
12556 nameXMMReg( gregOfRM(modrm) ) );
12557 } else {
12558 addr = disAMode( &alen, sorb, delta+3, dis_buf );
12559 assign( src, loadLE( isD ? Ity_F64 : Ity_F32, mkexpr(addr) ));
12560 imm = insn[3+alen];
12561 if (imm & ~3) goto decode_failure;
12562 delta += 3+alen+1;
12563 DIP( "roundsd $%d,%s,%s\n",
12564 imm, dis_buf, nameXMMReg( gregOfRM(modrm) ) );
12565 }
12566
12567 /* (imm & 3) contains an Intel-encoded rounding mode. Because
12568 that encoding is the same as the encoding for IRRoundingMode,
12569 we can use that value directly in the IR as a rounding
12570 mode. */
12571 assign(res, binop(isD ? Iop_RoundF64toInt : Iop_RoundF32toInt,
12572 mkU32(imm & 3), mkexpr(src)) );
12573
12574 if (isD)
12575 putXMMRegLane64F( gregOfRM(modrm), 0, mkexpr(res) );
12576 else
12577 putXMMRegLane32F( gregOfRM(modrm), 0, mkexpr(res) );
12578
12579 goto decode_success;
12580 }
12581
12582 /* ---------------------------------------------------- */
12583 /* --- end of the SSE4 decoder --- */
12584 /* ---------------------------------------------------- */
12585
sewardj9df271d2004-12-31 22:37:42 +000012586 after_sse_decoders:
12587
sewardjdc5d0842006-11-16 10:42:02 +000012588 /* ---------------------------------------------------- */
12589 /* --- deal with misc 0x67 pfxs (addr size override) -- */
12590 /* ---------------------------------------------------- */
12591
12592 /* 67 E3 = JCXZ (for JECXZ see below) */
12593 if (insn[0] == 0x67 && insn[1] == 0xE3 && sz == 4) {
12594 delta += 2;
12595 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
12596 delta ++;
12597 stmt( IRStmt_Exit(
12598 binop(Iop_CmpEQ16, getIReg(2,R_ECX), mkU16(0)),
12599 Ijk_Boring,
12600 IRConst_U32(d32)
12601 ));
12602 DIP("jcxz 0x%x\n", d32);
12603 goto decode_success;
12604 }
12605
12606 /* ---------------------------------------------------- */
12607 /* --- start of the baseline insn decoder -- */
12608 /* ---------------------------------------------------- */
12609
sewardjc9a65702004-07-07 16:32:57 +000012610 /* Get the primary opcode. */
12611 opc = getIByte(delta); delta++;
12612
12613 /* We get here if the current insn isn't SSE, or this CPU doesn't
12614 support SSE. */
12615
12616 switch (opc) {
12617
12618 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +000012619
12620 case 0xC2: /* RET imm16 */
12621 d32 = getUDisp16(delta);
12622 delta += 2;
12623 dis_ret(d32);
sewardj9e6491a2005-07-02 19:24:10 +000012624 dres.whatNext = Dis_StopHere;
sewardj2d49b432005-02-01 00:37:06 +000012625 DIP("ret %d\n", (Int)d32);
sewardj940e8c92004-07-11 16:53:24 +000012626 break;
sewardje05c42c2004-07-08 20:25:10 +000012627 case 0xC3: /* RET */
12628 dis_ret(0);
sewardj9e6491a2005-07-02 19:24:10 +000012629 dres.whatNext = Dis_StopHere;
sewardje05c42c2004-07-08 20:25:10 +000012630 DIP("ret\n");
12631 break;
sewardj0e9a0f52008-01-04 01:22:41 +000012632
12633 case 0xCF: /* IRET */
12634 /* Note, this is an extremely kludgey and limited implementation
12635 of iret. All it really does is:
12636 popl %EIP; popl %CS; popl %EFLAGS.
12637 %CS is set but ignored (as it is in (eg) popw %cs)". */
12638 t1 = newTemp(Ity_I32); /* ESP */
12639 t2 = newTemp(Ity_I32); /* new EIP */
12640 t3 = newTemp(Ity_I32); /* new CS */
12641 t4 = newTemp(Ity_I32); /* new EFLAGS */
12642 assign(t1, getIReg(4,R_ESP));
12643 assign(t2, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(0) )));
12644 assign(t3, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(4) )));
12645 assign(t4, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(8) )));
12646 /* Get stuff off stack */
12647 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(12)));
12648 /* set %CS (which is ignored anyway) */
12649 putSReg( R_CS, unop(Iop_32to16, mkexpr(t3)) );
12650 /* set %EFLAGS */
12651 set_EFLAGS_from_value( t4, False/*!emit_AC_emwarn*/, 0/*unused*/ );
12652 /* goto new EIP value */
12653 jmp_treg(Ijk_Ret,t2);
12654 dres.whatNext = Dis_StopHere;
12655 DIP("iret (very kludgey)\n");
12656 break;
12657
sewardjd1061ab2004-07-08 01:45:30 +000012658 case 0xE8: /* CALL J4 */
12659 d32 = getUDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000012660 d32 += (guest_EIP_bbstart+delta);
sewardjce70a5c2004-10-18 14:09:54 +000012661 /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
sewardj9e6491a2005-07-02 19:24:10 +000012662 if (d32 == guest_EIP_bbstart+delta && getIByte(delta) >= 0x58
sewardjce70a5c2004-10-18 14:09:54 +000012663 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +000012664 /* Specially treat the position-independent-code idiom
12665 call X
12666 X: popl %reg
12667 as
12668 movl %eip, %reg.
12669 since this generates better code, but for no other reason. */
12670 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +000012671 /* vex_printf("-- fPIC thingy\n"); */
sewardj9e6491a2005-07-02 19:24:10 +000012672 putIReg(4, archReg, mkU32(guest_EIP_bbstart+delta));
sewardjd1061ab2004-07-08 01:45:30 +000012673 delta++; /* Step over the POP */
12674 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +000012675 } else {
sewardjd1061ab2004-07-08 01:45:30 +000012676 /* The normal sequence for a call. */
12677 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000012678 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
12679 putIReg(4, R_ESP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000012680 storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
sewardjc716aea2006-01-17 01:48:46 +000012681 if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32 )) {
sewardjce70a5c2004-10-18 14:09:54 +000012682 /* follow into the call target. */
sewardj984d9b12010-01-15 10:53:21 +000012683 dres.whatNext = Dis_ResteerU;
sewardj9e6491a2005-07-02 19:24:10 +000012684 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000012685 } else {
12686 jmp_lit(Ijk_Call,d32);
sewardj9e6491a2005-07-02 19:24:10 +000012687 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000012688 }
sewardjd1061ab2004-07-08 01:45:30 +000012689 DIP("call 0x%x\n",d32);
12690 }
12691 break;
12692
sewardjc9a65702004-07-07 16:32:57 +000012693//-- case 0xC8: /* ENTER */
12694//-- d32 = getUDisp16(eip); eip += 2;
12695//-- abyte = getIByte(delta); delta++;
12696//--
12697//-- vg_assert(sz == 4);
12698//-- vg_assert(abyte == 0);
12699//--
12700//-- t1 = newTemp(cb); t2 = newTemp(cb);
12701//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
12702//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
12703//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
12704//-- uLiteral(cb, sz);
12705//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
12706//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
12707//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
12708//-- if (d32) {
12709//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
sewardj5bd4d162004-11-10 13:02:48 +000012710//-- uLiteral(cb, d32);
12711//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
sewardjc9a65702004-07-07 16:32:57 +000012712//-- }
12713//-- DIP("enter 0x%x, 0x%x", d32, abyte);
12714//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +000012715
12716 case 0xC9: /* LEAVE */
12717 vassert(sz == 4);
12718 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
12719 assign(t1, getIReg(4,R_EBP));
12720 /* First PUT ESP looks redundant, but need it because ESP must
12721 always be up-to-date for Memcheck to work... */
12722 putIReg(4, R_ESP, mkexpr(t1));
12723 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
12724 putIReg(4, R_EBP, mkexpr(t2));
12725 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
12726 DIP("leave\n");
12727 break;
12728
sewardj8edc36b2007-11-23 02:46:29 +000012729 /* ---------------- Misc weird-ass insns --------------- */
12730
12731 case 0x27: /* DAA */
12732 case 0x2F: /* DAS */
12733 case 0x37: /* AAA */
12734 case 0x3F: /* AAS */
12735 /* An ugly implementation for some ugly instructions. Oh
12736 well. */
12737 if (sz != 4) goto decode_failure;
12738 t1 = newTemp(Ity_I32);
12739 t2 = newTemp(Ity_I32);
12740 /* Make up a 32-bit value (t1), with the old value of AX in the
12741 bottom 16 bits, and the old OSZACP bitmask in the upper 16
12742 bits. */
12743 assign(t1,
12744 binop(Iop_16HLto32,
12745 unop(Iop_32to16,
12746 mk_x86g_calculate_eflags_all()),
12747 getIReg(2, R_EAX)
12748 ));
12749 /* Call the helper fn, to get a new AX and OSZACP value, and
12750 poke both back into the guest state. Also pass the helper
12751 the actual opcode so it knows which of the 4 instructions it
12752 is doing the computation for. */
12753 vassert(opc == 0x27 || opc == 0x2F || opc == 0x37 || opc == 0x3F);
12754 assign(t2,
12755 mkIRExprCCall(
12756 Ity_I32, 0/*regparm*/, "x86g_calculate_daa_das_aaa_aas",
12757 &x86g_calculate_daa_das_aaa_aas,
12758 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
12759 ));
12760 putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
12761
12762 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
12763 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
12764 stmt( IRStmt_Put( OFFB_CC_DEP1,
12765 binop(Iop_And32,
12766 binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
12767 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
12768 | X86G_CC_MASK_A | X86G_CC_MASK_Z
12769 | X86G_CC_MASK_S| X86G_CC_MASK_O )
12770 )
12771 )
12772 );
12773 /* Set NDEP even though it isn't used. This makes redundant-PUT
12774 elimination of previous stores to this field work better. */
12775 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
12776 switch (opc) {
12777 case 0x27: DIP("daa\n"); break;
12778 case 0x2F: DIP("das\n"); break;
12779 case 0x37: DIP("aaa\n"); break;
12780 case 0x3F: DIP("aas\n"); break;
12781 default: vassert(0);
12782 }
12783 break;
12784
sewardjc9a65702004-07-07 16:32:57 +000012785//-- case 0xD4: /* AAM */
12786//-- case 0xD5: /* AAD */
12787//-- d32 = getIByte(delta); delta++;
12788//-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
12789//-- t1 = newTemp(cb);
12790//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
12791//-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
12792//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
12793//-- uWiden(cb, 2, False);
12794//-- uInstr0(cb, CALLM_S, 0);
12795//-- uInstr1(cb, PUSH, 4, TempReg, t1);
12796//-- uInstr1(cb, CALLM, 0, Lit16,
12797//-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
12798//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
12799//-- uInstr1(cb, POP, 4, TempReg, t1);
12800//-- uInstr0(cb, CALLM_E, 0);
12801//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
12802//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
12803//-- break;
sewardj1c6f9912004-09-07 10:15:24 +000012804
12805 /* ------------------------ CWD/CDQ -------------------- */
12806
12807 case 0x98: /* CBW */
12808 if (sz == 4) {
12809 putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
12810 DIP("cwde\n");
12811 } else {
sewardj47341042004-09-19 11:55:46 +000012812 vassert(sz == 2);
12813 putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
12814 DIP("cbw\n");
sewardj1c6f9912004-09-07 10:15:24 +000012815 }
12816 break;
sewardj64e1d652004-07-12 14:00:46 +000012817
12818 case 0x99: /* CWD/CDQ */
12819 ty = szToITy(sz);
12820 putIReg(sz, R_EDX,
12821 binop(mkSizedOp(ty,Iop_Sar8),
12822 getIReg(sz, R_EAX),
sewardj9ee82862004-12-14 01:16:59 +000012823 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +000012824 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
12825 break;
12826
sewardjbdc7d212004-09-09 02:46:40 +000012827 /* ------------------------ FPU ops -------------------- */
12828
12829 case 0x9E: /* SAHF */
12830 codegen_SAHF();
12831 DIP("sahf\n");
12832 break;
12833
sewardj8dfdc8a2005-10-03 11:39:02 +000012834 case 0x9F: /* LAHF */
12835 codegen_LAHF();
12836 DIP("lahf\n");
12837 break;
12838
sewardjbdc7d212004-09-09 02:46:40 +000012839 case 0x9B: /* FWAIT */
12840 /* ignore? */
12841 DIP("fwait\n");
12842 break;
12843
sewardjd1725d12004-08-12 20:46:53 +000012844 case 0xD8:
12845 case 0xD9:
12846 case 0xDA:
12847 case 0xDB:
12848 case 0xDC:
12849 case 0xDD:
12850 case 0xDE:
12851 case 0xDF: {
sewardj52d04912005-07-03 00:52:48 +000012852 Int delta0 = delta;
sewardjd1725d12004-08-12 20:46:53 +000012853 Bool decode_OK = False;
12854 delta = dis_FPU ( &decode_OK, sorb, delta );
12855 if (!decode_OK) {
12856 delta = delta0;
12857 goto decode_failure;
12858 }
12859 break;
12860 }
sewardj0611d802004-07-11 02:37:54 +000012861
12862 /* ------------------------ INC & DEC ------------------ */
12863
12864 case 0x40: /* INC eAX */
12865 case 0x41: /* INC eCX */
12866 case 0x42: /* INC eDX */
12867 case 0x43: /* INC eBX */
12868 case 0x44: /* INC eSP */
12869 case 0x45: /* INC eBP */
12870 case 0x46: /* INC eSI */
12871 case 0x47: /* INC eDI */
12872 vassert(sz == 2 || sz == 4);
12873 ty = szToITy(sz);
12874 t1 = newTemp(ty);
12875 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
12876 getIReg(sz, (UInt)(opc - 0x40)),
12877 mkU(ty,1)) );
12878 setFlags_INC_DEC( True, t1, ty );
12879 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
12880 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
12881 break;
12882
12883 case 0x48: /* DEC eAX */
12884 case 0x49: /* DEC eCX */
12885 case 0x4A: /* DEC eDX */
12886 case 0x4B: /* DEC eBX */
12887 case 0x4C: /* DEC eSP */
12888 case 0x4D: /* DEC eBP */
12889 case 0x4E: /* DEC eSI */
12890 case 0x4F: /* DEC eDI */
12891 vassert(sz == 2 || sz == 4);
12892 ty = szToITy(sz);
12893 t1 = newTemp(ty);
12894 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
12895 getIReg(sz, (UInt)(opc - 0x48)),
12896 mkU(ty,1)) );
12897 setFlags_INC_DEC( False, t1, ty );
12898 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
12899 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
12900 break;
12901
12902 /* ------------------------ INT ------------------------ */
12903
sewardj322bfa02007-02-28 23:31:42 +000012904 case 0xCC: /* INT 3 */
sewardj0f500042007-08-29 09:09:17 +000012905 jmp_lit(Ijk_SigTRAP,((Addr32)guest_EIP_bbstart)+delta);
sewardj322bfa02007-02-28 23:31:42 +000012906 dres.whatNext = Dis_StopHere;
12907 DIP("int $0x3\n");
12908 break;
12909
sewardj0611d802004-07-11 02:37:54 +000012910 case 0xCD: /* INT imm8 */
12911 d32 = getIByte(delta); delta++;
sewardj0f500042007-08-29 09:09:17 +000012912
sewardjd660d412008-12-03 21:29:59 +000012913 /* For any of the cases where we emit a jump (that is, for all
12914 currently handled cases), it's important that all ArchRegs
12915 carry their up-to-date value at this point. So we declare an
12916 end-of-block here, which forces any TempRegs caching ArchRegs
12917 to be flushed. */
12918
sewardj0f500042007-08-29 09:09:17 +000012919 /* Handle int $0x40 .. $0x43 by synthesising a segfault and a
12920 restart of this instruction (hence the "-2" two lines below,
12921 to get the restart EIP to be this instruction. This is
12922 probably Linux-specific and it would be more correct to only
12923 do this if the VexAbiInfo says that is what we should do. */
12924 if (d32 >= 0x40 && d32 <= 0x43) {
12925 jmp_lit(Ijk_SigSEGV,((Addr32)guest_EIP_bbstart)+delta-2);
12926 dres.whatNext = Dis_StopHere;
12927 DIP("int $0x%x\n", (Int)d32);
12928 break;
12929 }
12930
sewardjd660d412008-12-03 21:29:59 +000012931 /* Handle int $0x80 (linux syscalls), int $0x81 and $0x82
sewardje86310f2009-03-19 22:21:40 +000012932 (darwin syscalls). As part of this, note where we are, so we
12933 can back up the guest to this point if the syscall needs to
12934 be restarted. */
sewardjd660d412008-12-03 21:29:59 +000012935 if (d32 == 0x80) {
sewardje86310f2009-03-19 22:21:40 +000012936 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
12937 mkU32(guest_EIP_curr_instr) ) );
sewardjd660d412008-12-03 21:29:59 +000012938 jmp_lit(Ijk_Sys_int128,((Addr32)guest_EIP_bbstart)+delta);
12939 dres.whatNext = Dis_StopHere;
12940 DIP("int $0x80\n");
12941 break;
12942 }
12943 if (d32 == 0x81) {
sewardje86310f2009-03-19 22:21:40 +000012944 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
12945 mkU32(guest_EIP_curr_instr) ) );
sewardjd660d412008-12-03 21:29:59 +000012946 jmp_lit(Ijk_Sys_int129,((Addr32)guest_EIP_bbstart)+delta);
12947 dres.whatNext = Dis_StopHere;
12948 DIP("int $0x81\n");
12949 break;
12950 }
12951 if (d32 == 0x82) {
sewardje86310f2009-03-19 22:21:40 +000012952 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
12953 mkU32(guest_EIP_curr_instr) ) );
sewardjd660d412008-12-03 21:29:59 +000012954 jmp_lit(Ijk_Sys_int130,((Addr32)guest_EIP_bbstart)+delta);
12955 dres.whatNext = Dis_StopHere;
12956 DIP("int $0x82\n");
12957 break;
12958 }
12959
12960 /* none of the above */
12961 goto decode_failure;
sewardj0611d802004-07-11 02:37:54 +000012962
sewardj77b86be2004-07-11 13:28:24 +000012963 /* ------------------------ Jcond, byte offset --------- */
12964
12965 case 0xEB: /* Jb (jump, byte offset) */
sewardj9e6491a2005-07-02 19:24:10 +000012966 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardj77b86be2004-07-11 13:28:24 +000012967 delta++;
sewardjc716aea2006-01-17 01:48:46 +000012968 if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
sewardj984d9b12010-01-15 10:53:21 +000012969 dres.whatNext = Dis_ResteerU;
sewardj9e6491a2005-07-02 19:24:10 +000012970 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000012971 } else {
12972 jmp_lit(Ijk_Boring,d32);
sewardj9e6491a2005-07-02 19:24:10 +000012973 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000012974 }
sewardj77b86be2004-07-11 13:28:24 +000012975 DIP("jmp-8 0x%x\n", d32);
12976 break;
sewardj0611d802004-07-11 02:37:54 +000012977
12978 case 0xE9: /* Jv (jump, 16/32 offset) */
12979 vassert(sz == 4); /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000012980 d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta);
sewardj0611d802004-07-11 02:37:54 +000012981 delta += sz;
sewardjc716aea2006-01-17 01:48:46 +000012982 if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
sewardj984d9b12010-01-15 10:53:21 +000012983 dres.whatNext = Dis_ResteerU;
sewardj9e6491a2005-07-02 19:24:10 +000012984 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000012985 } else {
12986 jmp_lit(Ijk_Boring,d32);
sewardj9e6491a2005-07-02 19:24:10 +000012987 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000012988 }
sewardj0611d802004-07-11 02:37:54 +000012989 DIP("jmp 0x%x\n", d32);
12990 break;
sewardje87b4842004-07-10 12:23:30 +000012991
12992 case 0x70:
12993 case 0x71:
12994 case 0x72: /* JBb/JNAEb (jump below) */
12995 case 0x73: /* JNBb/JAEb (jump not below) */
12996 case 0x74: /* JZb/JEb (jump zero) */
12997 case 0x75: /* JNZb/JNEb (jump not zero) */
12998 case 0x76: /* JBEb/JNAb (jump below or equal) */
12999 case 0x77: /* JNBEb/JAb (jump not below or equal) */
13000 case 0x78: /* JSb (jump negative) */
13001 case 0x79: /* JSb (jump not negative) */
13002 case 0x7A: /* JP (jump parity even) */
13003 case 0x7B: /* JNP/JPO (jump parity odd) */
13004 case 0x7C: /* JLb/JNGEb (jump less) */
13005 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
13006 case 0x7E: /* JLEb/JNGb (jump less or equal) */
13007 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj984d9b12010-01-15 10:53:21 +000013008 { Int jmpDelta;
13009 HChar* comment = "";
13010 jmpDelta = (Int)getSDisp8(delta);
13011 vassert(-128 <= jmpDelta && jmpDelta < 128);
13012 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + jmpDelta;
sewardje87b4842004-07-10 12:23:30 +000013013 delta++;
sewardj984d9b12010-01-15 10:53:21 +000013014 if (resteerCisOk
13015 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000013016 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000013017 && jmpDelta < 0
13018 && resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
13019 /* Speculation: assume this backward branch is taken. So we
13020 need to emit a side-exit to the insn following this one,
13021 on the negation of the condition, and continue at the
sewardj0d925b12010-01-17 15:47:01 +000013022 branch target address (d32). If we wind up back at the
13023 first instruction of the trace, just stop; it's better to
13024 let the IR loop unroller handle that case. */
sewardjdbf550c2005-01-24 11:54:11 +000013025 stmt( IRStmt_Exit(
13026 mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
13027 Ijk_Boring,
sewardj9e6491a2005-07-02 19:24:10 +000013028 IRConst_U32(guest_EIP_bbstart+delta) ) );
sewardj984d9b12010-01-15 10:53:21 +000013029 dres.whatNext = Dis_ResteerC;
sewardj9e6491a2005-07-02 19:24:10 +000013030 dres.continueAt = (Addr64)(Addr32)d32;
sewardj984d9b12010-01-15 10:53:21 +000013031 comment = "(assumed taken)";
13032 }
13033 else
13034 if (resteerCisOk
13035 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000013036 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000013037 && jmpDelta >= 0
13038 && resteerOkFn( callback_opaque,
13039 (Addr64)(Addr32)(guest_EIP_bbstart+delta)) ) {
13040 /* Speculation: assume this forward branch is not taken. So
13041 we need to emit a side-exit to d32 (the dest) and continue
13042 disassembling at the insn immediately following this
13043 one. */
13044 stmt( IRStmt_Exit(
13045 mk_x86g_calculate_condition((X86Condcode)(opc - 0x70)),
13046 Ijk_Boring,
13047 IRConst_U32(d32) ) );
13048 dres.whatNext = Dis_ResteerC;
13049 dres.continueAt = (Addr64)(Addr32)(guest_EIP_bbstart+delta);
13050 comment = "(assumed not taken)";
13051 }
13052 else {
13053 /* Conservative default translation - end the block at this
13054 point. */
13055 jcc_01( (X86Condcode)(opc - 0x70),
13056 (Addr32)(guest_EIP_bbstart+delta), d32);
sewardj9e6491a2005-07-02 19:24:10 +000013057 dres.whatNext = Dis_StopHere;
sewardjdbf550c2005-01-24 11:54:11 +000013058 }
sewardj984d9b12010-01-15 10:53:21 +000013059 DIP("j%s-8 0x%x %s\n", name_X86Condcode(opc - 0x70), d32, comment);
sewardje87b4842004-07-10 12:23:30 +000013060 break;
sewardj984d9b12010-01-15 10:53:21 +000013061 }
sewardje87b4842004-07-10 12:23:30 +000013062
sewardjdc5d0842006-11-16 10:42:02 +000013063 case 0xE3: /* JECXZ (for JCXZ see above) */
sewardjbaa66082005-08-23 17:29:27 +000013064 if (sz != 4) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000013065 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardjdc5d0842006-11-16 10:42:02 +000013066 delta ++;
sewardj458a6f82004-08-25 12:46:02 +000013067 stmt( IRStmt_Exit(
sewardjdc5d0842006-11-16 10:42:02 +000013068 binop(Iop_CmpEQ32, getIReg(4,R_ECX), mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +000013069 Ijk_Boring,
sewardjdc5d0842006-11-16 10:42:02 +000013070 IRConst_U32(d32)
13071 ));
13072 DIP("jecxz 0x%x\n", d32);
sewardj458a6f82004-08-25 12:46:02 +000013073 break;
13074
sewardjbaa66082005-08-23 17:29:27 +000013075 case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
13076 case 0xE1: /* LOOPE disp8: decrement count, jump if count != 0 && ZF==1 */
13077 case 0xE2: /* LOOP disp8: decrement count, jump if count != 0 */
13078 { /* Again, the docs say this uses ECX/CX as a count depending on
13079 the address size override, not the operand one. Since we
13080 don't handle address size overrides, I guess that means
13081 ECX. */
13082 IRExpr* zbit = NULL;
13083 IRExpr* count = NULL;
13084 IRExpr* cond = NULL;
13085 HChar* xtra = NULL;
13086
13087 if (sz != 4) goto decode_failure;
13088 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13089 delta++;
13090 putIReg(4, R_ECX, binop(Iop_Sub32, getIReg(4,R_ECX), mkU32(1)));
13091
13092 count = getIReg(4,R_ECX);
13093 cond = binop(Iop_CmpNE32, count, mkU32(0));
13094 switch (opc) {
13095 case 0xE2:
13096 xtra = "";
13097 break;
13098 case 0xE1:
13099 xtra = "e";
13100 zbit = mk_x86g_calculate_condition( X86CondZ );
13101 cond = mkAnd1(cond, zbit);
13102 break;
13103 case 0xE0:
13104 xtra = "ne";
13105 zbit = mk_x86g_calculate_condition( X86CondNZ );
13106 cond = mkAnd1(cond, zbit);
13107 break;
13108 default:
13109 vassert(0);
13110 }
13111 stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U32(d32)) );
13112
13113 DIP("loop%s 0x%x\n", xtra, d32);
13114 break;
13115 }
sewardj1813dbe2004-07-28 17:09:04 +000013116
13117 /* ------------------------ IMUL ----------------------- */
13118
13119 case 0x69: /* IMUL Iv, Ev, Gv */
13120 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
13121 break;
13122 case 0x6B: /* IMUL Ib, Ev, Gv */
13123 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
13124 break;
sewardj0611d802004-07-11 02:37:54 +000013125
13126 /* ------------------------ MOV ------------------------ */
13127
13128 case 0x88: /* MOV Gb,Eb */
13129 delta = dis_mov_G_E(sorb, 1, delta);
13130 break;
sewardjc9a65702004-07-07 16:32:57 +000013131
13132 case 0x89: /* MOV Gv,Ev */
13133 delta = dis_mov_G_E(sorb, sz, delta);
13134 break;
13135
sewardjc2ac51e2004-07-12 01:03:26 +000013136 case 0x8A: /* MOV Eb,Gb */
13137 delta = dis_mov_E_G(sorb, 1, delta);
13138 break;
sewardje05c42c2004-07-08 20:25:10 +000013139
13140 case 0x8B: /* MOV Ev,Gv */
13141 delta = dis_mov_E_G(sorb, sz, delta);
13142 break;
13143
sewardje87b4842004-07-10 12:23:30 +000013144 case 0x8D: /* LEA M,Gv */
sewardje9460bd2005-01-28 13:45:42 +000013145 if (sz != 4)
13146 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000013147 modrm = getIByte(delta);
13148 if (epartIsReg(modrm))
sewardje9460bd2005-01-28 13:45:42 +000013149 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000013150 /* NOTE! this is the one place where a segment override prefix
13151 has no effect on the address calculation. Therefore we pass
13152 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +000013153 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
13154 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +000013155 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +000013156 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
13157 nameIReg(sz,gregOfRM(modrm)));
13158 break;
sewardje05c42c2004-07-08 20:25:10 +000013159
sewardj063f02f2004-10-20 12:36:12 +000013160 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
13161 delta = dis_mov_Sw_Ew(sorb, sz, delta);
13162 break;
13163
sewardj7df596b2004-12-06 14:29:12 +000013164 case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
13165 delta = dis_mov_Ew_Sw(sorb, delta);
13166 break;
13167
sewardj43852812004-10-16 23:10:08 +000013168 case 0xA0: /* MOV Ob,AL */
13169 sz = 1;
13170 /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +000013171 case 0xA1: /* MOV Ov,eAX */
13172 d32 = getUDisp32(delta); delta += 4;
13173 ty = szToITy(sz);
13174 addr = newTemp(Ity_I32);
13175 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13176 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
13177 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
13178 d32, nameIReg(sz,R_EAX));
13179 break;
13180
sewardj180e8b32004-07-29 01:40:11 +000013181 case 0xA2: /* MOV Ob,AL */
13182 sz = 1;
13183 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +000013184 case 0xA3: /* MOV eAX,Ov */
13185 d32 = getUDisp32(delta); delta += 4;
13186 ty = szToITy(sz);
13187 addr = newTemp(Ity_I32);
13188 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13189 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
13190 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
13191 sorbTxt(sorb), d32);
13192 break;
sewardje87b4842004-07-10 12:23:30 +000013193
sewardjc2ac51e2004-07-12 01:03:26 +000013194 case 0xB0: /* MOV imm,AL */
13195 case 0xB1: /* MOV imm,CL */
13196 case 0xB2: /* MOV imm,DL */
13197 case 0xB3: /* MOV imm,BL */
13198 case 0xB4: /* MOV imm,AH */
13199 case 0xB5: /* MOV imm,CH */
13200 case 0xB6: /* MOV imm,DH */
13201 case 0xB7: /* MOV imm,BH */
13202 d32 = getIByte(delta); delta += 1;
13203 putIReg(1, opc-0xB0, mkU8(d32));
13204 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
13205 break;
sewardj7ed22952004-07-29 00:09:58 +000013206
sewardje87b4842004-07-10 12:23:30 +000013207 case 0xB8: /* MOV imm,eAX */
13208 case 0xB9: /* MOV imm,eCX */
13209 case 0xBA: /* MOV imm,eDX */
13210 case 0xBB: /* MOV imm,eBX */
13211 case 0xBC: /* MOV imm,eSP */
13212 case 0xBD: /* MOV imm,eBP */
13213 case 0xBE: /* MOV imm,eSI */
13214 case 0xBF: /* MOV imm,eDI */
13215 d32 = getUDisp(sz,delta); delta += sz;
13216 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
13217 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
13218 break;
13219
sewardj77b86be2004-07-11 13:28:24 +000013220 case 0xC6: /* MOV Ib,Eb */
13221 sz = 1;
13222 goto do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +000013223 case 0xC7: /* MOV Iv,Ev */
13224 goto do_Mov_I_E;
13225
13226 do_Mov_I_E:
13227 modrm = getIByte(delta);
13228 if (epartIsReg(modrm)) {
13229 delta++; /* mod/rm byte */
13230 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000013231 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000013232 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
13233 nameIReg(sz,eregOfRM(modrm)));
sewardje87b4842004-07-10 12:23:30 +000013234 } else {
13235 addr = disAMode ( &alen, sorb, delta, dis_buf );
13236 delta += alen;
13237 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000013238 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000013239 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
13240 }
13241 break;
13242
sewardj1813dbe2004-07-28 17:09:04 +000013243 /* ------------------------ opl imm, A ----------------- */
13244
13245 case 0x04: /* ADD Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013246 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj1813dbe2004-07-28 17:09:04 +000013247 break;
sewardj77b86be2004-07-11 13:28:24 +000013248 case 0x05: /* ADD Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013249 delta = dis_op_imm_A( sz, False, Iop_Add8, True, delta, "add" );
sewardj77b86be2004-07-11 13:28:24 +000013250 break;
13251
sewardj940e8c92004-07-11 16:53:24 +000013252 case 0x0C: /* OR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013253 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000013254 break;
sewardj82292882004-07-27 00:15:59 +000013255 case 0x0D: /* OR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013256 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj82292882004-07-27 00:15:59 +000013257 break;
13258
sewardjeca20362005-08-24 09:22:39 +000013259 case 0x14: /* ADC Ib, AL */
13260 delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
13261 break;
sewardja718d5d2005-04-03 14:59:54 +000013262 case 0x15: /* ADC Iv, eAX */
sewardjeca20362005-08-24 09:22:39 +000013263 delta = dis_op_imm_A( sz, True, Iop_Add8, True, delta, "adc" );
sewardja718d5d2005-04-03 14:59:54 +000013264 break;
13265
sewardj2fbae082005-10-03 02:07:08 +000013266 case 0x1C: /* SBB Ib, AL */
13267 delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
13268 break;
13269 case 0x1D: /* SBB Iv, eAX */
13270 delta = dis_op_imm_A( sz, True, Iop_Sub8, True, delta, "sbb" );
13271 break;
13272
sewardj940e8c92004-07-11 16:53:24 +000013273 case 0x24: /* AND Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013274 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj940e8c92004-07-11 16:53:24 +000013275 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013276 case 0x25: /* AND Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013277 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardjc2ac51e2004-07-12 01:03:26 +000013278 break;
sewardj0611d802004-07-11 02:37:54 +000013279
13280 case 0x2C: /* SUB Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013281 delta = dis_op_imm_A( 1, False, Iop_Sub8, True, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000013282 break;
sewardj68511542004-07-28 00:15:44 +000013283 case 0x2D: /* SUB Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013284 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj68511542004-07-28 00:15:44 +000013285 break;
13286
sewardj1c6f9912004-09-07 10:15:24 +000013287 case 0x34: /* XOR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013288 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj1c6f9912004-09-07 10:15:24 +000013289 break;
sewardjcaca9d02004-07-28 07:11:32 +000013290 case 0x35: /* XOR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013291 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardjcaca9d02004-07-28 07:11:32 +000013292 break;
13293
sewardj0611d802004-07-11 02:37:54 +000013294 case 0x3C: /* CMP Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013295 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000013296 break;
13297 case 0x3D: /* CMP Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013298 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000013299 break;
13300
sewardj77b86be2004-07-11 13:28:24 +000013301 case 0xA8: /* TEST Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013302 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj77b86be2004-07-11 13:28:24 +000013303 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013304 case 0xA9: /* TEST Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013305 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardjc2ac51e2004-07-12 01:03:26 +000013306 break;
13307
sewardj1c6f9912004-09-07 10:15:24 +000013308 /* ------------------------ opl Ev, Gv ----------------- */
13309
sewardj89cd0932004-09-08 18:23:25 +000013310 case 0x02: /* ADD Eb,Gb */
13311 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
13312 break;
sewardj9334b0f2004-07-10 22:43:54 +000013313 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013314 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +000013315 break;
13316
sewardj7ed22952004-07-29 00:09:58 +000013317 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013318 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +000013319 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013320 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013321 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +000013322 break;
sewardj2fbae082005-10-03 02:07:08 +000013323
13324 case 0x12: /* ADC Eb,Gb */
13325 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
13326 break;
sewardjc4eaff32004-09-10 20:25:11 +000013327 case 0x13: /* ADC Ev,Gv */
13328 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
13329 break;
13330
sewardj2fbae082005-10-03 02:07:08 +000013331 case 0x1A: /* SBB Eb,Gb */
13332 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
13333 break;
sewardj180e8b32004-07-29 01:40:11 +000013334 case 0x1B: /* SBB Ev,Gv */
13335 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +000013336 break;
13337
sewardj1c6f9912004-09-07 10:15:24 +000013338 case 0x22: /* AND Eb,Gb */
13339 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
13340 break;
sewardj180e8b32004-07-29 01:40:11 +000013341 case 0x23: /* AND Ev,Gv */
13342 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
13343 break;
13344
13345 case 0x2A: /* SUB Eb,Gb */
13346 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
13347 break;
sewardj0611d802004-07-11 02:37:54 +000013348 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013349 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000013350 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013351
13352 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013353 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000013354 break;
sewardj1813dbe2004-07-28 17:09:04 +000013355 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013356 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +000013357 break;
13358
sewardjc2ac51e2004-07-12 01:03:26 +000013359 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013360 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +000013361 break;
sewardje90ad6a2004-07-10 19:02:10 +000013362 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013363 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000013364 break;
13365
sewardj0611d802004-07-11 02:37:54 +000013366 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013367 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +000013368 break;
sewardje05c42c2004-07-08 20:25:10 +000013369 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013370 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +000013371 break;
13372
sewardj180e8b32004-07-29 01:40:11 +000013373 /* ------------------------ opl Gv, Ev ----------------- */
13374
13375 case 0x00: /* ADD Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013376 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13377 Iop_Add8, True, 1, delta, "add" );
sewardj180e8b32004-07-29 01:40:11 +000013378 break;
sewardje05c42c2004-07-08 20:25:10 +000013379 case 0x01: /* ADD Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013380 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13381 Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +000013382 break;
13383
sewardj940e8c92004-07-11 16:53:24 +000013384 case 0x08: /* OR Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013385 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13386 Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000013387 break;
sewardj9334b0f2004-07-10 22:43:54 +000013388 case 0x09: /* OR Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013389 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13390 Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +000013391 break;
13392
sewardja2384712004-07-29 14:36:40 +000013393 case 0x10: /* ADC Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013394 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13395 Iop_Add8, True, 1, delta, "adc" );
sewardja2384712004-07-29 14:36:40 +000013396 break;
sewardjcaca9d02004-07-28 07:11:32 +000013397 case 0x11: /* ADC Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013398 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13399 Iop_Add8, True, sz, delta, "adc" );
sewardjcaca9d02004-07-28 07:11:32 +000013400 break;
13401
sewardja2384712004-07-29 14:36:40 +000013402 case 0x18: /* SBB Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013403 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13404 Iop_Sub8, True, 1, delta, "sbb" );
sewardja2384712004-07-29 14:36:40 +000013405 break;
sewardjcaca9d02004-07-28 07:11:32 +000013406 case 0x19: /* SBB Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013407 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13408 Iop_Sub8, True, sz, delta, "sbb" );
sewardjcaca9d02004-07-28 07:11:32 +000013409 break;
13410
sewardja2384712004-07-29 14:36:40 +000013411 case 0x20: /* AND Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013412 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13413 Iop_And8, True, 1, delta, "and" );
sewardja2384712004-07-29 14:36:40 +000013414 break;
sewardj0611d802004-07-11 02:37:54 +000013415 case 0x21: /* AND Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013416 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13417 Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +000013418 break;
13419
sewardj180e8b32004-07-29 01:40:11 +000013420 case 0x28: /* SUB Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013421 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13422 Iop_Sub8, True, 1, delta, "sub" );
sewardj180e8b32004-07-29 01:40:11 +000013423 break;
sewardje05c42c2004-07-08 20:25:10 +000013424 case 0x29: /* SUB Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013425 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13426 Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +000013427 break;
13428
sewardjc2ac51e2004-07-12 01:03:26 +000013429 case 0x30: /* XOR Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013430 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13431 Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000013432 break;
sewardje87b4842004-07-10 12:23:30 +000013433 case 0x31: /* XOR Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013434 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13435 Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +000013436 break;
13437
sewardj0611d802004-07-11 02:37:54 +000013438 case 0x38: /* CMP Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013439 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13440 Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000013441 break;
sewardje90ad6a2004-07-10 19:02:10 +000013442 case 0x39: /* CMP Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013443 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13444 Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000013445 break;
13446
sewardj9334b0f2004-07-10 22:43:54 +000013447 /* ------------------------ POP ------------------------ */
13448
13449 case 0x58: /* POP eAX */
13450 case 0x59: /* POP eCX */
13451 case 0x5A: /* POP eDX */
13452 case 0x5B: /* POP eBX */
13453 case 0x5D: /* POP eBP */
13454 case 0x5E: /* POP eSI */
13455 case 0x5F: /* POP eDI */
13456 case 0x5C: /* POP eSP */
13457 vassert(sz == 2 || sz == 4);
13458 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
13459 assign(t2, getIReg(4, R_ESP));
13460 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
13461 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
13462 putIReg(sz, opc-0x58, mkexpr(t1));
13463 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
13464 break;
13465
sewardja2384712004-07-29 14:36:40 +000013466 case 0x9D: /* POPF */
13467 vassert(sz == 2 || sz == 4);
sewardja2384712004-07-29 14:36:40 +000013468 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13469 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +000013470 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +000013471 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
sewardja2384712004-07-29 14:36:40 +000013472
sewardj0e9a0f52008-01-04 01:22:41 +000013473 /* Generate IR to set %EFLAGS{O,S,Z,A,C,P,D,ID,AC} from the
13474 value in t1. */
13475 set_EFLAGS_from_value( t1, True/*emit_AC_emwarn*/,
13476 ((Addr32)guest_EIP_bbstart)+delta );
sewardj6d269842005-08-06 11:45:02 +000013477
sewardja2384712004-07-29 14:36:40 +000013478 DIP("popf%c\n", nameISize(sz));
13479 break;
13480
sewardjbbdc6222004-12-15 18:43:39 +000013481 case 0x61: /* POPA */
13482 /* This is almost certainly wrong for sz==2. So ... */
13483 if (sz != 4) goto decode_failure;
13484
13485 /* t5 is the old %ESP value. */
13486 t5 = newTemp(Ity_I32);
13487 assign( t5, getIReg(4, R_ESP) );
13488
13489 /* Reload all the registers, except %esp. */
13490 putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
13491 putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
13492 putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
13493 putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
13494 /* ignore saved %ESP */
13495 putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
13496 putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
13497 putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
13498
13499 /* and move %ESP back up */
13500 putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
13501
sewardja3d1a662005-03-29 21:33:11 +000013502 DIP("popa%c\n", nameISize(sz));
sewardjbbdc6222004-12-15 18:43:39 +000013503 break;
sewardjfeeb8a82004-11-30 12:30:11 +000013504
13505 case 0x8F: /* POPL/POPW m32 */
sewardjfcff1782006-05-12 14:04:48 +000013506 { Int len;
13507 UChar rm = getIByte(delta);
sewardjfeeb8a82004-11-30 12:30:11 +000013508
13509 /* make sure this instruction is correct POP */
sewardjfcff1782006-05-12 14:04:48 +000013510 if (epartIsReg(rm) || gregOfRM(rm) != 0)
13511 goto decode_failure;
sewardjfeeb8a82004-11-30 12:30:11 +000013512 /* and has correct size */
sewardjfcff1782006-05-12 14:04:48 +000013513 if (sz != 4 && sz != 2)
13514 goto decode_failure;
13515 ty = szToITy(sz);
13516
13517 t1 = newTemp(Ity_I32); /* stack address */
13518 t3 = newTemp(ty); /* data */
sewardjfeeb8a82004-11-30 12:30:11 +000013519 /* set t1 to ESP: t1 = ESP */
13520 assign( t1, getIReg(4, R_ESP) );
13521 /* load M[ESP] to virtual register t3: t3 = M[t1] */
sewardjfcff1782006-05-12 14:04:48 +000013522 assign( t3, loadLE(ty, mkexpr(t1)) );
sewardjfeeb8a82004-11-30 12:30:11 +000013523
13524 /* increase ESP; must be done before the STORE. Intel manual says:
13525 If the ESP register is used as a base register for addressing
13526 a destination operand in memory, the POP instruction computes
13527 the effective address of the operand after it increments the
13528 ESP register.
13529 */
13530 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
13531
13532 /* resolve MODR/M */
13533 addr = disAMode ( &len, sorb, delta, dis_buf);
13534 storeLE( mkexpr(addr), mkexpr(t3) );
13535
sewardjfcff1782006-05-12 14:04:48 +000013536 DIP("pop%c %s\n", sz==2 ? 'w' : 'l', dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +000013537
13538 delta += len;
13539 break;
13540 }
13541
sewardj5c5f72c2006-03-18 11:29:25 +000013542 case 0x1F: /* POP %DS */
13543 dis_pop_segreg( R_DS, sz ); break;
13544 case 0x07: /* POP %ES */
13545 dis_pop_segreg( R_ES, sz ); break;
13546 case 0x17: /* POP %SS */
13547 dis_pop_segreg( R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +000013548
13549 /* ------------------------ PUSH ----------------------- */
13550
13551 case 0x50: /* PUSH eAX */
13552 case 0x51: /* PUSH eCX */
13553 case 0x52: /* PUSH eDX */
13554 case 0x53: /* PUSH eBX */
13555 case 0x55: /* PUSH eBP */
13556 case 0x56: /* PUSH eSI */
13557 case 0x57: /* PUSH eDI */
13558 case 0x54: /* PUSH eSP */
13559 /* This is the Right Way, in that the value to be pushed is
13560 established before %esp is changed, so that pushl %esp
13561 correctly pushes the old value. */
13562 vassert(sz == 2 || sz == 4);
13563 ty = sz==2 ? Ity_I16 : Ity_I32;
sewardj883b00b2004-09-11 09:30:24 +000013564 t1 = newTemp(ty); t2 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000013565 assign(t1, getIReg(sz, opc-0x50));
13566 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
13567 putIReg(4, R_ESP, mkexpr(t2) );
13568 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +000013569 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
13570 break;
13571
13572
sewardj0c12ea82004-07-12 08:18:16 +000013573 case 0x68: /* PUSH Iv */
13574 d32 = getUDisp(sz,delta); delta += sz;
13575 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +000013576 case 0x6A: /* PUSH Ib, sign-extended to sz */
13577 d32 = getSDisp8(delta); delta += 1;
13578 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +000013579 do_push_I:
13580 ty = szToITy(sz);
13581 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
13582 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
13583 putIReg(4, R_ESP, mkexpr(t1) );
sewardjc4255a02006-08-28 18:04:33 +000013584 /* stop mkU16 asserting if d32 is a negative 16-bit number
13585 (bug #132813) */
13586 if (ty == Ity_I16)
13587 d32 &= 0xFFFF;
sewardj0c12ea82004-07-12 08:18:16 +000013588 storeLE( mkexpr(t1), mkU(ty,d32) );
13589 DIP("push%c $0x%x\n", nameISize(sz), d32);
13590 break;
13591
sewardja2384712004-07-29 14:36:40 +000013592 case 0x9C: /* PUSHF */ {
sewardja2384712004-07-29 14:36:40 +000013593 vassert(sz == 2 || sz == 4);
sewardja2384712004-07-29 14:36:40 +000013594
13595 t1 = newTemp(Ity_I32);
13596 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
13597 putIReg(4, R_ESP, mkexpr(t1) );
13598
sewardjbc210942005-07-21 10:07:13 +000013599 /* Calculate OSZACP, and patch in fixed fields as per
13600 Intel docs.
13601 - bit 1 is always 1
13602 - bit 9 is Interrupt Enable (should always be 1 in user mode?)
13603 */
sewardja2384712004-07-29 14:36:40 +000013604 t2 = newTemp(Ity_I32);
sewardjbc210942005-07-21 10:07:13 +000013605 assign( t2, binop(Iop_Or32,
13606 mk_x86g_calculate_eflags_all(),
13607 mkU32( (1<<1)|(1<<9) ) ));
sewardja2384712004-07-29 14:36:40 +000013608
sewardjf9c74fe2004-12-16 02:54:54 +000013609 /* Patch in the D flag. This can simply be a copy of bit 10 of
13610 baseBlock[OFFB_DFLAG]. */
sewardja2384712004-07-29 14:36:40 +000013611 t3 = newTemp(Ity_I32);
13612 assign( t3, binop(Iop_Or32,
13613 mkexpr(t2),
13614 binop(Iop_And32,
sewardjf9c74fe2004-12-16 02:54:54 +000013615 IRExpr_Get(OFFB_DFLAG,Ity_I32),
sewardj5bd4d162004-11-10 13:02:48 +000013616 mkU32(1<<10)))
sewardja2384712004-07-29 14:36:40 +000013617 );
sewardj006a6a22004-10-26 00:50:52 +000013618
13619 /* And patch in the ID flag. */
13620 t4 = newTemp(Ity_I32);
13621 assign( t4, binop(Iop_Or32,
13622 mkexpr(t3),
13623 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +000013624 binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
sewardj006a6a22004-10-26 00:50:52 +000013625 mkU8(21)),
sewardj5bd4d162004-11-10 13:02:48 +000013626 mkU32(1<<21)))
sewardj006a6a22004-10-26 00:50:52 +000013627 );
13628
sewardj6d269842005-08-06 11:45:02 +000013629 /* And patch in the AC flag. */
13630 t5 = newTemp(Ity_I32);
13631 assign( t5, binop(Iop_Or32,
13632 mkexpr(t4),
13633 binop(Iop_And32,
13634 binop(Iop_Shl32, IRExpr_Get(OFFB_ACFLAG,Ity_I32),
13635 mkU8(18)),
13636 mkU32(1<<18)))
13637 );
13638
sewardja2384712004-07-29 14:36:40 +000013639 /* if sz==2, the stored value needs to be narrowed. */
13640 if (sz == 2)
sewardj6d269842005-08-06 11:45:02 +000013641 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t5)) );
sewardja2384712004-07-29 14:36:40 +000013642 else
sewardj6d269842005-08-06 11:45:02 +000013643 storeLE( mkexpr(t1), mkexpr(t5) );
sewardja2384712004-07-29 14:36:40 +000013644
13645 DIP("pushf%c\n", nameISize(sz));
13646 break;
13647 }
13648
sewardjbbdc6222004-12-15 18:43:39 +000013649 case 0x60: /* PUSHA */
13650 /* This is almost certainly wrong for sz==2. So ... */
13651 if (sz != 4) goto decode_failure;
13652
13653 /* This is the Right Way, in that the value to be pushed is
13654 established before %esp is changed, so that pusha
13655 correctly pushes the old %esp value. New value of %esp is
13656 pushed at start. */
13657 /* t0 is the %ESP value we're going to push. */
13658 t0 = newTemp(Ity_I32);
13659 assign( t0, getIReg(4, R_ESP) );
13660
13661 /* t5 will be the new %ESP value. */
13662 t5 = newTemp(Ity_I32);
13663 assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
13664
13665 /* Update guest state before prodding memory. */
13666 putIReg(4, R_ESP, mkexpr(t5));
13667
13668 /* Dump all the registers. */
13669 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
13670 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
13671 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
13672 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
13673 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
13674 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
13675 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
13676 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
13677
13678 DIP("pusha%c\n", nameISize(sz));
13679 break;
13680
sewardj5c5f72c2006-03-18 11:29:25 +000013681 case 0x0E: /* PUSH %CS */
13682 dis_push_segreg( R_CS, sz ); break;
13683 case 0x1E: /* PUSH %DS */
13684 dis_push_segreg( R_DS, sz ); break;
13685 case 0x06: /* PUSH %ES */
13686 dis_push_segreg( R_ES, sz ); break;
13687 case 0x16: /* PUSH %SS */
13688 dis_push_segreg( R_SS, sz ); break;
sewardj458a6f82004-08-25 12:46:02 +000013689
13690 /* ------------------------ SCAS et al ----------------- */
13691
13692 case 0xA4: /* MOVS, no REP prefix */
13693 case 0xA5:
sewardj9c3b25a2007-04-05 15:06:56 +000013694 if (sorb != 0)
13695 goto decode_failure; /* else dis_string_op asserts */
sewardj458a6f82004-08-25 12:46:02 +000013696 dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
13697 break;
13698
sewardj8d4d2232005-01-20 10:47:46 +000013699 case 0xA6: /* CMPSb, no REP prefix */
sewardj33b53542005-03-11 14:00:27 +000013700 case 0xA7:
sewardj9c3b25a2007-04-05 15:06:56 +000013701 if (sorb != 0)
13702 goto decode_failure; /* else dis_string_op asserts */
13703 dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
13704 break;
sewardj33b53542005-03-11 14:00:27 +000013705
sewardj883b00b2004-09-11 09:30:24 +000013706 case 0xAA: /* STOS, no REP prefix */
sewardj47341042004-09-19 11:55:46 +000013707 case 0xAB:
sewardj9c3b25a2007-04-05 15:06:56 +000013708 if (sorb != 0)
13709 goto decode_failure; /* else dis_string_op asserts */
sewardj883b00b2004-09-11 09:30:24 +000013710 dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
13711 break;
sewardj33b53542005-03-11 14:00:27 +000013712
sewardj10ca4eb2005-05-30 11:19:54 +000013713 case 0xAC: /* LODS, no REP prefix */
13714 case 0xAD:
sewardj9c3b25a2007-04-05 15:06:56 +000013715 if (sorb != 0)
13716 goto decode_failure; /* else dis_string_op asserts */
sewardj10ca4eb2005-05-30 11:19:54 +000013717 dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
13718 break;
sewardj2d4c3a02004-10-15 00:03:23 +000013719
13720 case 0xAE: /* SCAS, no REP prefix */
13721 case 0xAF:
sewardj9c3b25a2007-04-05 15:06:56 +000013722 if (sorb != 0)
13723 goto decode_failure; /* else dis_string_op asserts */
sewardj2d4c3a02004-10-15 00:03:23 +000013724 dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
13725 break;
sewardj64e1d652004-07-12 14:00:46 +000013726
13727
13728 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +000013729 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +000013730 DIP("cld\n");
13731 break;
13732
sewardj1813dbe2004-07-28 17:09:04 +000013733 case 0xFD: /* STD */
13734 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
13735 DIP("std\n");
13736 break;
13737
sewardjbc210942005-07-21 10:07:13 +000013738 case 0xF8: /* CLC */
13739 case 0xF9: /* STC */
13740 case 0xF5: /* CMC */
13741 t0 = newTemp(Ity_I32);
13742 t1 = newTemp(Ity_I32);
13743 assign( t0, mk_x86g_calculate_eflags_all() );
13744 switch (opc) {
13745 case 0xF8:
13746 assign( t1, binop(Iop_And32, mkexpr(t0),
13747 mkU32(~X86G_CC_MASK_C)));
13748 DIP("clc\n");
13749 break;
13750 case 0xF9:
13751 assign( t1, binop(Iop_Or32, mkexpr(t0),
13752 mkU32(X86G_CC_MASK_C)));
13753 DIP("stc\n");
13754 break;
13755 case 0xF5:
13756 assign( t1, binop(Iop_Xor32, mkexpr(t0),
13757 mkU32(X86G_CC_MASK_C)));
13758 DIP("cmc\n");
13759 break;
13760 default:
13761 vpanic("disInstr(x86)(clc/stc/cmc)");
13762 }
13763 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
13764 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13765 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
13766 /* Set NDEP even though it isn't used. This makes redundant-PUT
13767 elimination of previous stores to this field work better. */
13768 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13769 break;
sewardj82292882004-07-27 00:15:59 +000013770
sewardja384eb92007-11-16 02:30:38 +000013771 case 0xD6: /* SALC */
13772 t0 = newTemp(Ity_I32);
13773 t1 = newTemp(Ity_I32);
13774 assign( t0, binop(Iop_And32,
13775 mk_x86g_calculate_eflags_c(),
13776 mkU32(1)) );
13777 assign( t1, binop(Iop_Sar32,
13778 binop(Iop_Shl32, mkexpr(t0), mkU8(31)),
13779 mkU8(31)) );
13780 putIReg(1, R_EAX, unop(Iop_32to8, mkexpr(t1)) );
13781 DIP("salc\n");
13782 break;
13783
sewardj82292882004-07-27 00:15:59 +000013784 /* REPNE prefix insn */
13785 case 0xF2: {
sewardj068baa22008-05-11 10:11:58 +000013786 Addr32 eip_orig = guest_EIP_bbstart + delta_start;
sewardj9c3b25a2007-04-05 15:06:56 +000013787 if (sorb != 0) goto decode_failure;
sewardj82292882004-07-27 00:15:59 +000013788 abyte = getIByte(delta); delta++;
13789
13790 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj9e6491a2005-07-02 19:24:10 +000013791 dres.whatNext = Dis_StopHere;
sewardj82292882004-07-27 00:15:59 +000013792
13793 switch (abyte) {
13794 /* According to the Intel manual, "repne movs" should never occur, but
13795 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +000013796 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardjcea96622006-11-14 15:33:05 +000013797 case 0xA5:
13798 dis_REP_op ( X86CondNZ, dis_MOVS, sz, eip_orig,
13799 guest_EIP_bbstart+delta, "repne movs" );
13800 break;
sewardj842dfb42008-05-09 08:53:50 +000013801
13802 case 0xA6: sz = 1; /* REPNE CMP<sz> */
13803 case 0xA7:
13804 dis_REP_op ( X86CondNZ, dis_CMPS, sz, eip_orig,
13805 guest_EIP_bbstart+delta, "repne cmps" );
13806 break;
13807
sewardjb69a6fa2006-11-14 15:13:55 +000013808 case 0xAA: sz = 1; /* REPNE STOS<sz> */
13809 case 0xAB:
13810 dis_REP_op ( X86CondNZ, dis_STOS, sz, eip_orig,
13811 guest_EIP_bbstart+delta, "repne stos" );
13812 break;
13813
sewardj82292882004-07-27 00:15:59 +000013814 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000013815 case 0xAF:
sewardj2a9ad022004-11-25 02:46:58 +000013816 dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000013817 guest_EIP_bbstart+delta, "repne scas" );
sewardj82292882004-07-27 00:15:59 +000013818 break;
13819
13820 default:
13821 goto decode_failure;
13822 }
13823 break;
13824 }
sewardj64e1d652004-07-12 14:00:46 +000013825
13826 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
13827 for the rest, it means REP) */
13828 case 0xF3: {
sewardj068baa22008-05-11 10:11:58 +000013829 Addr32 eip_orig = guest_EIP_bbstart + delta_start;
sewardj9c3b25a2007-04-05 15:06:56 +000013830 if (sorb != 0) goto decode_failure;
sewardj64e1d652004-07-12 14:00:46 +000013831 abyte = getIByte(delta); delta++;
13832
13833 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj9e6491a2005-07-02 19:24:10 +000013834 dres.whatNext = Dis_StopHere;
sewardj64e1d652004-07-12 14:00:46 +000013835
13836 switch (abyte) {
13837 case 0xA4: sz = 1; /* REP MOVS<sz> */
13838 case 0xA5:
sewardj2a9ad022004-11-25 02:46:58 +000013839 dis_REP_op ( X86CondAlways, dis_MOVS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000013840 guest_EIP_bbstart+delta, "rep movs" );
sewardj64e1d652004-07-12 14:00:46 +000013841 break;
13842
13843 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000013844 case 0xA7:
sewardj2a9ad022004-11-25 02:46:58 +000013845 dis_REP_op ( X86CondZ, dis_CMPS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000013846 guest_EIP_bbstart+delta, "repe cmps" );
sewardj64e1d652004-07-12 14:00:46 +000013847 break;
13848
13849 case 0xAA: sz = 1; /* REP STOS<sz> */
13850 case 0xAB:
sewardj2a9ad022004-11-25 02:46:58 +000013851 dis_REP_op ( X86CondAlways, dis_STOS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000013852 guest_EIP_bbstart+delta, "rep stos" );
sewardj64e1d652004-07-12 14:00:46 +000013853 break;
sewardj576f3232006-04-12 17:30:46 +000013854
sewardjdfb038d2007-11-25 01:34:03 +000013855 case 0xAC: sz = 1; /* REP LODS<sz> */
13856 case 0xAD:
13857 dis_REP_op ( X86CondAlways, dis_LODS, sz, eip_orig,
13858 guest_EIP_bbstart+delta, "rep lods" );
13859 break;
13860
sewardj576f3232006-04-12 17:30:46 +000013861 case 0xAE: sz = 1; /* REPE SCAS<sz> */
13862 case 0xAF:
13863 dis_REP_op ( X86CondZ, dis_SCAS, sz, eip_orig,
13864 guest_EIP_bbstart+delta, "repe scas" );
13865 break;
sewardj43b8df12004-11-26 12:18:51 +000013866
13867 case 0x90: /* REP NOP (PAUSE) */
13868 /* a hint to the P4 re spin-wait loop */
13869 DIP("rep nop (P4 pause)\n");
sewardj7ec59f62005-03-12 16:47:18 +000013870 /* "observe" the hint. The Vex client needs to be careful not
13871 to cause very long delays as a result, though. */
sewardj9e6491a2005-07-02 19:24:10 +000013872 jmp_lit(Ijk_Yield, ((Addr32)guest_EIP_bbstart)+delta);
13873 dres.whatNext = Dis_StopHere;
sewardj43b8df12004-11-26 12:18:51 +000013874 break;
13875
sewardj7d3d3472005-08-12 23:51:31 +000013876 case 0xC3: /* REP RET -- same as normal ret? */
13877 dis_ret(0);
13878 dres.whatNext = Dis_StopHere;
13879 DIP("rep ret\n");
13880 break;
sewardj64e1d652004-07-12 14:00:46 +000013881
13882 default:
13883 goto decode_failure;
13884 }
13885 break;
13886 }
sewardj0611d802004-07-11 02:37:54 +000013887
13888 /* ------------------------ XCHG ----------------------- */
13889
sewardjc4356f02007-11-09 21:15:04 +000013890 /* XCHG reg,mem automatically asserts LOCK# even without a LOCK
sewardj1fb8c922009-07-12 12:56:53 +000013891 prefix; hence it must be translated with an IRCAS (at least, the
13892 memory variant). */
sewardj0611d802004-07-11 02:37:54 +000013893 case 0x86: /* XCHG Gb,Eb */
13894 sz = 1;
13895 /* Fall through ... */
13896 case 0x87: /* XCHG Gv,Ev */
13897 modrm = getIByte(delta);
13898 ty = szToITy(sz);
13899 t1 = newTemp(ty); t2 = newTemp(ty);
13900 if (epartIsReg(modrm)) {
sewardj5bd4d162004-11-10 13:02:48 +000013901 assign(t1, getIReg(sz, eregOfRM(modrm)));
13902 assign(t2, getIReg(sz, gregOfRM(modrm)));
13903 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
13904 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +000013905 delta++;
13906 DIP("xchg%c %s, %s\n",
13907 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
13908 nameIReg(sz,eregOfRM(modrm)));
13909 } else {
sewardje9d8a262009-07-01 08:06:34 +000013910 *expect_CAS = True;
sewardj0c12ea82004-07-12 08:18:16 +000013911 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj5bd4d162004-11-10 13:02:48 +000013912 assign( t1, loadLE(ty,mkexpr(addr)) );
13913 assign( t2, getIReg(sz,gregOfRM(modrm)) );
sewardje9d8a262009-07-01 08:06:34 +000013914 casLE( mkexpr(addr),
13915 mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
sewardj5bd4d162004-11-10 13:02:48 +000013916 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
13917 delta += alen;
sewardj0611d802004-07-11 02:37:54 +000013918 DIP("xchg%c %s, %s\n", nameISize(sz),
13919 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +000013920 }
13921 break;
sewardje87b4842004-07-10 12:23:30 +000013922
13923 case 0x90: /* XCHG eAX,eAX */
13924 DIP("nop\n");
13925 break;
sewardj64e1d652004-07-12 14:00:46 +000013926 case 0x91: /* XCHG eAX,eCX */
13927 case 0x92: /* XCHG eAX,eDX */
13928 case 0x93: /* XCHG eAX,eBX */
13929 case 0x94: /* XCHG eAX,eSP */
13930 case 0x95: /* XCHG eAX,eBP */
13931 case 0x96: /* XCHG eAX,eSI */
13932 case 0x97: /* XCHG eAX,eDI */
13933 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
13934 break;
13935
sewardj048de4d2006-11-12 22:25:21 +000013936 /* ------------------------ XLAT ----------------------- */
13937
13938 case 0xD7: /* XLAT */
13939 if (sz != 4) goto decode_failure; /* sz == 2 is also allowed (0x66) */
13940 putIReg(
13941 1,
13942 R_EAX/*AL*/,
13943 loadLE(Ity_I8,
13944 handleSegOverride(
13945 sorb,
13946 binop(Iop_Add32,
13947 getIReg(4, R_EBX),
13948 unop(Iop_8Uto32, getIReg(1, R_EAX/*AL*/))))));
13949
13950 DIP("xlat%c [ebx]\n", nameISize(sz));
13951 break;
sewardjd14c5702005-10-29 19:19:51 +000013952
13953 /* ------------------------ IN / OUT ----------------------- */
13954
13955 case 0xE4: /* IN imm8, AL */
13956 sz = 1;
13957 t1 = newTemp(Ity_I32);
13958 abyte = getIByte(delta); delta++;
13959 assign(t1, mkU32( abyte & 0xFF ));
13960 DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX));
13961 goto do_IN;
13962 case 0xE5: /* IN imm8, eAX */
13963 vassert(sz == 2 || sz == 4);
13964 t1 = newTemp(Ity_I32);
13965 abyte = getIByte(delta); delta++;
13966 assign(t1, mkU32( abyte & 0xFF ));
13967 DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX));
13968 goto do_IN;
13969 case 0xEC: /* IN %DX, AL */
13970 sz = 1;
13971 t1 = newTemp(Ity_I32);
13972 assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
13973 DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
13974 nameIReg(sz,R_EAX));
13975 goto do_IN;
13976 case 0xED: /* IN %DX, eAX */
13977 vassert(sz == 2 || sz == 4);
13978 t1 = newTemp(Ity_I32);
13979 assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
13980 DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
13981 nameIReg(sz,R_EAX));
13982 goto do_IN;
13983 do_IN: {
13984 /* At this point, sz indicates the width, and t1 is a 32-bit
13985 value giving port number. */
13986 IRDirty* d;
13987 vassert(sz == 1 || sz == 2 || sz == 4);
13988 ty = szToITy(sz);
13989 t2 = newTemp(Ity_I32);
13990 d = unsafeIRDirty_1_N(
13991 t2,
13992 0/*regparms*/,
13993 "x86g_dirtyhelper_IN",
13994 &x86g_dirtyhelper_IN,
13995 mkIRExprVec_2( mkexpr(t1), mkU32(sz) )
13996 );
13997 /* do the call, dumping the result in t2. */
13998 stmt( IRStmt_Dirty(d) );
13999 putIReg(sz, R_EAX, narrowTo( ty, mkexpr(t2) ) );
14000 break;
14001 }
14002
14003 case 0xE6: /* OUT AL, imm8 */
14004 sz = 1;
14005 t1 = newTemp(Ity_I32);
14006 abyte = getIByte(delta); delta++;
14007 assign( t1, mkU32( abyte & 0xFF ) );
14008 DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte);
14009 goto do_OUT;
14010 case 0xE7: /* OUT eAX, imm8 */
14011 vassert(sz == 2 || sz == 4);
14012 t1 = newTemp(Ity_I32);
14013 abyte = getIByte(delta); delta++;
14014 assign( t1, mkU32( abyte & 0xFF ) );
14015 DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte);
14016 goto do_OUT;
14017 case 0xEE: /* OUT AL, %DX */
14018 sz = 1;
14019 t1 = newTemp(Ity_I32);
14020 assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14021 DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14022 nameIReg(2,R_EDX));
14023 goto do_OUT;
14024 case 0xEF: /* OUT eAX, %DX */
14025 vassert(sz == 2 || sz == 4);
14026 t1 = newTemp(Ity_I32);
14027 assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14028 DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14029 nameIReg(2,R_EDX));
14030 goto do_OUT;
14031 do_OUT: {
14032 /* At this point, sz indicates the width, and t1 is a 32-bit
14033 value giving port number. */
14034 IRDirty* d;
14035 vassert(sz == 1 || sz == 2 || sz == 4);
14036 ty = szToITy(sz);
14037 d = unsafeIRDirty_0_N(
14038 0/*regparms*/,
14039 "x86g_dirtyhelper_OUT",
14040 &x86g_dirtyhelper_OUT,
14041 mkIRExprVec_3( mkexpr(t1),
14042 widenUto32( getIReg(sz, R_EAX) ),
14043 mkU32(sz) )
14044 );
14045 stmt( IRStmt_Dirty(d) );
14046 break;
14047 }
sewardj0611d802004-07-11 02:37:54 +000014048
14049 /* ------------------------ (Grp1 extensions) ---------- */
14050
sewardj792d7712008-10-31 21:27:38 +000014051 case 0x82: /* Grp1 Ib,Eb too. Apparently this is the same as
14052 case 0x80, but only in 32-bit mode. */
14053 /* fallthru */
sewardj0611d802004-07-11 02:37:54 +000014054 case 0x80: /* Grp1 Ib,Eb */
14055 modrm = getIByte(delta);
14056 am_sz = lengthAMode(delta);
14057 sz = 1;
14058 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +000014059 d32 = getUChar(delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014060 delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
sewardj0611d802004-07-11 02:37:54 +000014061 break;
sewardje05c42c2004-07-08 20:25:10 +000014062
14063 case 0x81: /* Grp1 Iv,Ev */
14064 modrm = getIByte(delta);
14065 am_sz = lengthAMode(delta);
14066 d_sz = sz;
14067 d32 = getUDisp(d_sz, delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014068 delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
sewardje05c42c2004-07-08 20:25:10 +000014069 break;
sewardjd1061ab2004-07-08 01:45:30 +000014070
14071 case 0x83: /* Grp1 Ib,Ev */
14072 modrm = getIByte(delta);
14073 am_sz = lengthAMode(delta);
14074 d_sz = 1;
14075 d32 = getSDisp8(delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014076 delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
sewardjd1061ab2004-07-08 01:45:30 +000014077 break;
14078
sewardjc2ac51e2004-07-12 01:03:26 +000014079 /* ------------------------ (Grp2 extensions) ---------- */
14080
sewardjd51dc812007-03-20 14:18:45 +000014081 case 0xC0: { /* Grp2 Ib,Eb */
14082 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000014083 modrm = getIByte(delta);
14084 am_sz = lengthAMode(delta);
14085 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000014086 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +000014087 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +000014088 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014089 mkU8(d32 & 0xFF), NULL, &decode_OK );
14090 if (!decode_OK)
14091 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000014092 break;
sewardjd51dc812007-03-20 14:18:45 +000014093 }
14094 case 0xC1: { /* Grp2 Ib,Ev */
14095 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000014096 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +000014097 am_sz = lengthAMode(delta);
14098 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000014099 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +000014100 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014101 mkU8(d32 & 0xFF), NULL, &decode_OK );
14102 if (!decode_OK)
14103 goto decode_failure;
sewardje90ad6a2004-07-10 19:02:10 +000014104 break;
sewardjd51dc812007-03-20 14:18:45 +000014105 }
14106 case 0xD0: { /* Grp2 1,Eb */
14107 Bool decode_OK = True;
sewardj180e8b32004-07-29 01:40:11 +000014108 modrm = getIByte(delta);
14109 am_sz = lengthAMode(delta);
14110 d_sz = 0;
14111 d32 = 1;
14112 sz = 1;
14113 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014114 mkU8(d32), NULL, &decode_OK );
14115 if (!decode_OK)
14116 goto decode_failure;
sewardj180e8b32004-07-29 01:40:11 +000014117 break;
sewardjd51dc812007-03-20 14:18:45 +000014118 }
14119 case 0xD1: { /* Grp2 1,Ev */
14120 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000014121 modrm = getUChar(delta);
14122 am_sz = lengthAMode(delta);
14123 d_sz = 0;
14124 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +000014125 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014126 mkU8(d32), NULL, &decode_OK );
14127 if (!decode_OK)
14128 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000014129 break;
sewardjd51dc812007-03-20 14:18:45 +000014130 }
14131 case 0xD2: { /* Grp2 CL,Eb */
14132 Bool decode_OK = True;
sewardj8c7f1ab2004-07-29 20:31:09 +000014133 modrm = getUChar(delta);
14134 am_sz = lengthAMode(delta);
14135 d_sz = 0;
14136 sz = 1;
14137 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014138 getIReg(1,R_ECX), "%cl", &decode_OK );
14139 if (!decode_OK)
14140 goto decode_failure;
sewardj8c7f1ab2004-07-29 20:31:09 +000014141 break;
sewardjd51dc812007-03-20 14:18:45 +000014142 }
14143 case 0xD3: { /* Grp2 CL,Ev */
14144 Bool decode_OK = True;
sewardj9334b0f2004-07-10 22:43:54 +000014145 modrm = getIByte(delta);
14146 am_sz = lengthAMode(delta);
14147 d_sz = 0;
14148 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014149 getIReg(1,R_ECX), "%cl", &decode_OK );
14150 if (!decode_OK)
14151 goto decode_failure;
sewardj9334b0f2004-07-10 22:43:54 +000014152 break;
sewardjd51dc812007-03-20 14:18:45 +000014153 }
sewardj9334b0f2004-07-10 22:43:54 +000014154
sewardj940e8c92004-07-11 16:53:24 +000014155 /* ------------------------ (Grp3 extensions) ---------- */
14156
sewardjd51dc812007-03-20 14:18:45 +000014157 case 0xF6: { /* Grp3 Eb */
14158 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014159 delta = dis_Grp3 ( sorb, pfx_lock, 1, delta, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014160 if (!decode_OK)
14161 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000014162 break;
sewardjd51dc812007-03-20 14:18:45 +000014163 }
14164 case 0xF7: { /* Grp3 Ev */
14165 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014166 delta = dis_Grp3 ( sorb, pfx_lock, sz, delta, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014167 if (!decode_OK)
14168 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000014169 break;
sewardjd51dc812007-03-20 14:18:45 +000014170 }
sewardj940e8c92004-07-11 16:53:24 +000014171
sewardjc2ac51e2004-07-12 01:03:26 +000014172 /* ------------------------ (Grp4 extensions) ---------- */
14173
sewardjd51dc812007-03-20 14:18:45 +000014174 case 0xFE: { /* Grp4 Eb */
14175 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014176 delta = dis_Grp4 ( sorb, pfx_lock, delta, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014177 if (!decode_OK)
14178 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000014179 break;
sewardjd51dc812007-03-20 14:18:45 +000014180 }
sewardj0611d802004-07-11 02:37:54 +000014181
14182 /* ------------------------ (Grp5 extensions) ---------- */
14183
sewardjd51dc812007-03-20 14:18:45 +000014184 case 0xFF: { /* Grp5 Ev */
14185 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014186 delta = dis_Grp5 ( sorb, pfx_lock, sz, delta, &dres, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014187 if (!decode_OK)
14188 goto decode_failure;
sewardj0611d802004-07-11 02:37:54 +000014189 break;
sewardjd51dc812007-03-20 14:18:45 +000014190 }
sewardje87b4842004-07-10 12:23:30 +000014191
14192 /* ------------------------ Escapes to 2-byte opcodes -- */
14193
14194 case 0x0F: {
14195 opc = getIByte(delta); delta++;
14196 switch (opc) {
14197
sewardj490ad382005-03-13 17:25:53 +000014198 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
14199
14200 case 0xBA: { /* Grp8 Ib,Ev */
14201 Bool decode_OK = False;
14202 modrm = getUChar(delta);
14203 am_sz = lengthAMode(delta);
14204 d32 = getSDisp8(delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014205 delta = dis_Grp8_Imm ( sorb, pfx_lock, delta, modrm,
14206 am_sz, sz, d32, &decode_OK );
sewardj490ad382005-03-13 17:25:53 +000014207 if (!decode_OK)
14208 goto decode_failure;
14209 break;
14210 }
sewardjce646f22004-08-31 23:55:54 +000014211
14212 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
14213
14214 case 0xBC: /* BSF Gv,Ev */
14215 delta = dis_bs_E_G ( sorb, sz, delta, True );
14216 break;
14217 case 0xBD: /* BSR Gv,Ev */
14218 delta = dis_bs_E_G ( sorb, sz, delta, False );
14219 break;
sewardj1c4208f2004-08-25 13:25:29 +000014220
14221 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
14222
14223 case 0xC8: /* BSWAP %eax */
14224 case 0xC9:
14225 case 0xCA:
sewardjb4666cf2004-10-23 00:21:50 +000014226 case 0xCB:
14227 case 0xCC:
14228 case 0xCD:
sewardj1c4208f2004-08-25 13:25:29 +000014229 case 0xCE:
sewardj1c6f9912004-09-07 10:15:24 +000014230 case 0xCF: /* BSWAP %edi */
sewardj1c4208f2004-08-25 13:25:29 +000014231 /* AFAICS from the Intel docs, this only exists at size 4. */
14232 vassert(sz == 4);
14233 t1 = newTemp(Ity_I32);
14234 t2 = newTemp(Ity_I32);
14235 assign( t1, getIReg(4, opc-0xC8) );
14236
14237 assign( t2,
14238 binop(Iop_Or32,
14239 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
14240 binop(Iop_Or32,
14241 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
14242 mkU32(0x00FF0000)),
14243 binop(Iop_Or32,
14244 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
14245 mkU32(0x0000FF00)),
14246 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
14247 mkU32(0x000000FF) )
14248 )))
14249 );
14250
14251 putIReg(4, opc-0xC8, mkexpr(t2));
sewardj1c4208f2004-08-25 13:25:29 +000014252 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
14253 break;
14254
sewardj1c6f9912004-09-07 10:15:24 +000014255 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
14256
14257 case 0xA3: /* BT Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000014258 delta = dis_bt_G_E ( sorb, pfx_lock, sz, delta, BtOpNone );
sewardj1c6f9912004-09-07 10:15:24 +000014259 break;
sewardje6709112004-09-10 18:37:18 +000014260 case 0xB3: /* BTR Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000014261 delta = dis_bt_G_E ( sorb, pfx_lock, sz, delta, BtOpReset );
sewardje6709112004-09-10 18:37:18 +000014262 break;
sewardj1c6f9912004-09-07 10:15:24 +000014263 case 0xAB: /* BTS Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000014264 delta = dis_bt_G_E ( sorb, pfx_lock, sz, delta, BtOpSet );
sewardj1c6f9912004-09-07 10:15:24 +000014265 break;
sewardj4963a422004-10-14 23:34:03 +000014266 case 0xBB: /* BTC Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000014267 delta = dis_bt_G_E ( sorb, pfx_lock, sz, delta, BtOpComp );
sewardj4963a422004-10-14 23:34:03 +000014268 break;
sewardj458a6f82004-08-25 12:46:02 +000014269
14270 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
14271
sewardj2d4c3a02004-10-15 00:03:23 +000014272 case 0x40:
14273 case 0x41:
sewardj458a6f82004-08-25 12:46:02 +000014274 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
14275 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
14276 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
14277 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
14278 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
14279 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
sewardjce646f22004-08-31 23:55:54 +000014280 case 0x48: /* CMOVSb (cmov negative) */
sewardj458a6f82004-08-25 12:46:02 +000014281 case 0x49: /* CMOVSb (cmov not negative) */
sewardj2d4c3a02004-10-15 00:03:23 +000014282 case 0x4A: /* CMOVP (cmov parity even) */
14283 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardj458a6f82004-08-25 12:46:02 +000014284 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
14285 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
14286 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
14287 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj2a9ad022004-11-25 02:46:58 +000014288 delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
sewardj458a6f82004-08-25 12:46:02 +000014289 break;
14290
14291 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
14292
sewardjc744e872004-08-26 11:24:39 +000014293 case 0xB0: /* CMPXCHG Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000014294 delta = dis_cmpxchg_G_E ( sorb, pfx_lock, 1, delta );
sewardjc744e872004-08-26 11:24:39 +000014295 break;
sewardj458a6f82004-08-25 12:46:02 +000014296 case 0xB1: /* CMPXCHG Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000014297 delta = dis_cmpxchg_G_E ( sorb, pfx_lock, sz, delta );
sewardj458a6f82004-08-25 12:46:02 +000014298 break;
sewardj300bb872005-08-12 23:04:48 +000014299
14300 case 0xC7: { /* CMPXCHG8B Gv (0F C7 /1) */
sewardje9d8a262009-07-01 08:06:34 +000014301 IRTemp expdHi = newTemp(Ity_I32);
14302 IRTemp expdLo = newTemp(Ity_I32);
14303 IRTemp dataHi = newTemp(Ity_I32);
14304 IRTemp dataLo = newTemp(Ity_I32);
14305 IRTemp oldHi = newTemp(Ity_I32);
14306 IRTemp oldLo = newTemp(Ity_I32);
sewardj300bb872005-08-12 23:04:48 +000014307 IRTemp flags_old = newTemp(Ity_I32);
14308 IRTemp flags_new = newTemp(Ity_I32);
sewardje9d8a262009-07-01 08:06:34 +000014309 IRTemp success = newTemp(Ity_I1);
14310
14311 /* Translate this using a DCAS, even if there is no LOCK
14312 prefix. Life is too short to bother with generating two
14313 different translations for the with/without-LOCK-prefix
14314 cases. */
14315 *expect_CAS = True;
sewardj300bb872005-08-12 23:04:48 +000014316
14317 /* Decode, and generate address. */
sewardje9d8a262009-07-01 08:06:34 +000014318 if (sz != 4) goto decode_failure;
sewardj300bb872005-08-12 23:04:48 +000014319 modrm = getIByte(delta);
14320 if (epartIsReg(modrm)) goto decode_failure;
14321 if (gregOfRM(modrm) != 1) goto decode_failure;
14322 addr = disAMode ( &alen, sorb, delta, dis_buf );
14323 delta += alen;
14324
sewardje9d8a262009-07-01 08:06:34 +000014325 /* Get the expected and new values. */
14326 assign( expdHi, getIReg(4,R_EDX) );
14327 assign( expdLo, getIReg(4,R_EAX) );
14328 assign( dataHi, getIReg(4,R_ECX) );
14329 assign( dataLo, getIReg(4,R_EBX) );
sewardj300bb872005-08-12 23:04:48 +000014330
sewardje9d8a262009-07-01 08:06:34 +000014331 /* Do the DCAS */
14332 stmt( IRStmt_CAS(
14333 mkIRCAS( oldHi, oldLo,
14334 Iend_LE, mkexpr(addr),
14335 mkexpr(expdHi), mkexpr(expdLo),
14336 mkexpr(dataHi), mkexpr(dataLo)
14337 )));
sewardj300bb872005-08-12 23:04:48 +000014338
sewardje9d8a262009-07-01 08:06:34 +000014339 /* success when oldHi:oldLo == expdHi:expdLo */
14340 assign( success,
sewardj1fb8c922009-07-12 12:56:53 +000014341 binop(Iop_CasCmpEQ32,
sewardje9d8a262009-07-01 08:06:34 +000014342 binop(Iop_Or32,
14343 binop(Iop_Xor32, mkexpr(oldHi), mkexpr(expdHi)),
14344 binop(Iop_Xor32, mkexpr(oldLo), mkexpr(expdLo))
14345 ),
14346 mkU32(0)
14347 ));
sewardj300bb872005-08-12 23:04:48 +000014348
sewardje9d8a262009-07-01 08:06:34 +000014349 /* If the DCAS is successful, that is to say oldHi:oldLo ==
14350 expdHi:expdLo, then put expdHi:expdLo back in EDX:EAX,
14351 which is where they came from originally. Both the actual
14352 contents of these two regs, and any shadow values, are
14353 unchanged. If the DCAS fails then we're putting into
14354 EDX:EAX the value seen in memory. */
14355 putIReg(4, R_EDX,
14356 IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(success)),
14357 mkexpr(oldHi),
14358 mkexpr(expdHi)
14359 ));
14360 putIReg(4, R_EAX,
14361 IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(success)),
14362 mkexpr(oldLo),
14363 mkexpr(expdLo)
14364 ));
sewardj300bb872005-08-12 23:04:48 +000014365
sewardje9d8a262009-07-01 08:06:34 +000014366 /* Copy the success bit into the Z flag and leave the others
14367 unchanged */
sewardj300bb872005-08-12 23:04:48 +000014368 assign( flags_old, widenUto32(mk_x86g_calculate_eflags_all()));
14369 assign(
14370 flags_new,
14371 binop(Iop_Or32,
14372 binop(Iop_And32, mkexpr(flags_old),
14373 mkU32(~X86G_CC_MASK_Z)),
14374 binop(Iop_Shl32,
14375 binop(Iop_And32,
sewardje9d8a262009-07-01 08:06:34 +000014376 unop(Iop_1Uto32, mkexpr(success)), mkU32(1)),
sewardj300bb872005-08-12 23:04:48 +000014377 mkU8(X86G_CC_SHIFT_Z)) ));
14378
14379 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
14380 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
14381 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14382 /* Set NDEP even though it isn't used. This makes
14383 redundant-PUT elimination of previous stores to this field
14384 work better. */
14385 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14386
14387 /* Sheesh. Aren't you glad it was me and not you that had to
14388 write and validate all this grunge? */
14389
14390 DIP("cmpxchg8b %s\n", dis_buf);
14391 break;
14392 }
14393
sewardj588ea762004-09-10 18:56:32 +000014394 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
14395
sewardj7cb49d72004-10-24 22:31:25 +000014396 case 0xA2: { /* CPUID */
14397 /* Uses dirty helper:
sewardj9df271d2004-12-31 22:37:42 +000014398 void dirtyhelper_CPUID_sse[012] ( VexGuestX86State* )
sewardj7cb49d72004-10-24 22:31:25 +000014399 declared to mod eax, wr ebx, ecx, edx
14400 */
sewardj9df271d2004-12-31 22:37:42 +000014401 IRDirty* d = NULL;
14402 HChar* fName = NULL;
14403 void* fAddr = NULL;
sewardj5117ce12006-01-27 21:20:15 +000014404 if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2) {
14405 fName = "x86g_dirtyhelper_CPUID_sse2";
14406 fAddr = &x86g_dirtyhelper_CPUID_sse2;
14407 }
14408 else
14409 if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE1) {
14410 fName = "x86g_dirtyhelper_CPUID_sse1";
14411 fAddr = &x86g_dirtyhelper_CPUID_sse1;
14412 }
14413 else
14414 if (archinfo->hwcaps == 0/*no SSE*/) {
14415 fName = "x86g_dirtyhelper_CPUID_sse0";
14416 fAddr = &x86g_dirtyhelper_CPUID_sse0;
14417 } else
14418 vpanic("disInstr(x86)(cpuid)");
14419
sewardj9df271d2004-12-31 22:37:42 +000014420 vassert(fName); vassert(fAddr);
14421 d = unsafeIRDirty_0_N ( 0/*regparms*/,
14422 fName, fAddr, mkIRExprVec_0() );
sewardj7cb49d72004-10-24 22:31:25 +000014423 /* declare guest state effects */
sewardjc5fc7aa2004-10-27 23:00:55 +000014424 d->needsBBP = True;
sewardj7cb49d72004-10-24 22:31:25 +000014425 d->nFxState = 4;
14426 d->fxState[0].fx = Ifx_Modify;
14427 d->fxState[0].offset = OFFB_EAX;
14428 d->fxState[0].size = 4;
14429 d->fxState[1].fx = Ifx_Write;
14430 d->fxState[1].offset = OFFB_EBX;
14431 d->fxState[1].size = 4;
sewardj32bfd3e2008-02-10 13:29:19 +000014432 d->fxState[2].fx = Ifx_Modify;
sewardj7cb49d72004-10-24 22:31:25 +000014433 d->fxState[2].offset = OFFB_ECX;
14434 d->fxState[2].size = 4;
14435 d->fxState[3].fx = Ifx_Write;
14436 d->fxState[3].offset = OFFB_EDX;
14437 d->fxState[3].size = 4;
14438 /* execute the dirty call, side-effecting guest state */
14439 stmt( IRStmt_Dirty(d) );
sewardj55860d82005-01-08 18:25:05 +000014440 /* CPUID is a serialising insn. So, just in case someone is
14441 using it as a memory fence ... */
sewardjc4356f02007-11-09 21:15:04 +000014442 stmt( IRStmt_MBE(Imbe_Fence) );
sewardj517a7d62004-10-25 09:52:18 +000014443 DIP("cpuid\n");
sewardj588ea762004-09-10 18:56:32 +000014444 break;
sewardj7cb49d72004-10-24 22:31:25 +000014445 }
14446
sewardj5bd4d162004-11-10 13:02:48 +000014447//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
14448//-- goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000014449//--
14450//-- t1 = newTemp(cb);
14451//-- t2 = newTemp(cb);
14452//-- t3 = newTemp(cb);
14453//-- t4 = newTemp(cb);
14454//-- uInstr0(cb, CALLM_S, 0);
14455//--
14456//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
14457//-- uInstr1(cb, PUSH, 4, TempReg, t1);
14458//--
14459//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
14460//-- uLiteral(cb, 0);
14461//-- uInstr1(cb, PUSH, 4, TempReg, t2);
14462//--
14463//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
14464//-- uLiteral(cb, 0);
14465//-- uInstr1(cb, PUSH, 4, TempReg, t3);
14466//--
14467//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
14468//-- uLiteral(cb, 0);
14469//-- uInstr1(cb, PUSH, 4, TempReg, t4);
14470//--
14471//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
14472//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
14473//--
14474//-- uInstr1(cb, POP, 4, TempReg, t4);
14475//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
14476//--
14477//-- uInstr1(cb, POP, 4, TempReg, t3);
14478//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
14479//--
14480//-- uInstr1(cb, POP, 4, TempReg, t2);
14481//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
14482//--
14483//-- uInstr1(cb, POP, 4, TempReg, t1);
14484//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
14485//--
14486//-- uInstr0(cb, CALLM_E, 0);
14487//-- DIP("cpuid\n");
14488//-- break;
14489//--
sewardj9334b0f2004-07-10 22:43:54 +000014490 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
14491
14492 case 0xB6: /* MOVZXb Eb,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014493 if (sz != 2 && sz != 4)
14494 goto decode_failure;
14495 delta = dis_movx_E_G ( sorb, delta, 1, sz, False );
sewardj9334b0f2004-07-10 22:43:54 +000014496 break;
sewardj6ba982f2006-05-03 17:57:15 +000014497
sewardj940e8c92004-07-11 16:53:24 +000014498 case 0xB7: /* MOVZXw Ew,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014499 if (sz != 4)
14500 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000014501 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
14502 break;
14503
sewardj0611d802004-07-11 02:37:54 +000014504 case 0xBE: /* MOVSXb Eb,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014505 if (sz != 2 && sz != 4)
14506 goto decode_failure;
14507 delta = dis_movx_E_G ( sorb, delta, 1, sz, True );
sewardj0611d802004-07-11 02:37:54 +000014508 break;
sewardj6ba982f2006-05-03 17:57:15 +000014509
sewardj7ed22952004-07-29 00:09:58 +000014510 case 0xBF: /* MOVSXw Ew,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014511 if (sz != 4)
14512 goto decode_failure;
sewardj7ed22952004-07-29 00:09:58 +000014513 delta = dis_movx_E_G ( sorb, delta, 2, 4, True );
14514 break;
14515
sewardjc9a65702004-07-07 16:32:57 +000014516//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
14517//--
14518//-- case 0xC3: /* MOVNTI Gv,Ev */
14519//-- vg_assert(sz == 4);
14520//-- modrm = getUChar(eip);
14521//-- vg_assert(!epartIsReg(modrm));
14522//-- t1 = newTemp(cb);
14523//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
14524//-- pair = disAMode ( cb, sorb, eip, dis_buf );
14525//-- t2 = LOW24(pair);
14526//-- eip += HI8(pair);
14527//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
14528//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
14529//-- break;
sewardjcf780b42004-07-13 18:42:17 +000014530
14531 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
14532
14533 case 0xAF: /* IMUL Ev, Gv */
sewardj2a2ba8b2004-11-08 13:14:06 +000014534 delta = dis_mul_E_G ( sorb, sz, delta );
sewardjcf780b42004-07-13 18:42:17 +000014535 break;
sewardje87b4842004-07-10 12:23:30 +000014536
sewardjec387ca2006-08-01 18:36:25 +000014537 /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
14538
14539 case 0x1F:
14540 modrm = getUChar(delta);
14541 if (epartIsReg(modrm)) goto decode_failure;
14542 addr = disAMode ( &alen, sorb, delta, dis_buf );
14543 delta += alen;
14544 DIP("nop%c %s\n", nameISize(sz), dis_buf);
14545 break;
14546
sewardje87b4842004-07-10 12:23:30 +000014547 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
14548 case 0x80:
14549 case 0x81:
14550 case 0x82: /* JBb/JNAEb (jump below) */
14551 case 0x83: /* JNBb/JAEb (jump not below) */
14552 case 0x84: /* JZb/JEb (jump zero) */
14553 case 0x85: /* JNZb/JNEb (jump not zero) */
14554 case 0x86: /* JBEb/JNAb (jump below or equal) */
14555 case 0x87: /* JNBEb/JAb (jump not below or equal) */
14556 case 0x88: /* JSb (jump negative) */
14557 case 0x89: /* JSb (jump not negative) */
14558 case 0x8A: /* JP (jump parity even) */
14559 case 0x8B: /* JNP/JPO (jump parity odd) */
14560 case 0x8C: /* JLb/JNGEb (jump less) */
14561 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
14562 case 0x8E: /* JLEb/JNGb (jump less or equal) */
14563 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj984d9b12010-01-15 10:53:21 +000014564 { Int jmpDelta;
14565 HChar* comment = "";
14566 jmpDelta = (Int)getUDisp32(delta);
14567 d32 = (((Addr32)guest_EIP_bbstart)+delta+4) + jmpDelta;
sewardje87b4842004-07-10 12:23:30 +000014568 delta += 4;
sewardj984d9b12010-01-15 10:53:21 +000014569 if (resteerCisOk
14570 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000014571 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000014572 && jmpDelta < 0
14573 && resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
14574 /* Speculation: assume this backward branch is taken. So
14575 we need to emit a side-exit to the insn following this
14576 one, on the negation of the condition, and continue at
sewardj0d925b12010-01-17 15:47:01 +000014577 the branch target address (d32). If we wind up back at
14578 the first instruction of the trace, just stop; it's
14579 better to let the IR loop unroller handle that case.*/
sewardj984d9b12010-01-15 10:53:21 +000014580 stmt( IRStmt_Exit(
sewardj0d925b12010-01-17 15:47:01 +000014581 mk_x86g_calculate_condition((X86Condcode)
14582 (1 ^ (opc - 0x80))),
sewardj984d9b12010-01-15 10:53:21 +000014583 Ijk_Boring,
14584 IRConst_U32(guest_EIP_bbstart+delta) ) );
14585 dres.whatNext = Dis_ResteerC;
14586 dres.continueAt = (Addr64)(Addr32)d32;
14587 comment = "(assumed taken)";
14588 }
14589 else
14590 if (resteerCisOk
14591 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000014592 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000014593 && jmpDelta >= 0
14594 && resteerOkFn( callback_opaque,
14595 (Addr64)(Addr32)(guest_EIP_bbstart+delta)) ) {
14596 /* Speculation: assume this forward branch is not taken.
14597 So we need to emit a side-exit to d32 (the dest) and
14598 continue disassembling at the insn immediately
14599 following this one. */
14600 stmt( IRStmt_Exit(
14601 mk_x86g_calculate_condition((X86Condcode)(opc - 0x80)),
14602 Ijk_Boring,
14603 IRConst_U32(d32) ) );
14604 dres.whatNext = Dis_ResteerC;
14605 dres.continueAt = (Addr64)(Addr32)(guest_EIP_bbstart+delta);
14606 comment = "(assumed not taken)";
14607 }
14608 else {
14609 /* Conservative default translation - end the block at
14610 this point. */
14611 jcc_01( (X86Condcode)(opc - 0x80),
14612 (Addr32)(guest_EIP_bbstart+delta), d32);
14613 dres.whatNext = Dis_StopHere;
14614 }
14615 DIP("j%s-32 0x%x %s\n", name_X86Condcode(opc - 0x80), d32, comment);
sewardje87b4842004-07-10 12:23:30 +000014616 break;
sewardj984d9b12010-01-15 10:53:21 +000014617 }
sewardje87b4842004-07-10 12:23:30 +000014618
sewardj89cd0932004-09-08 18:23:25 +000014619 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
sewardj4ed64292005-08-23 19:24:29 +000014620 case 0x31: { /* RDTSC */
14621 IRTemp val = newTemp(Ity_I64);
14622 IRExpr** args = mkIRExprVec_0();
14623 IRDirty* d = unsafeIRDirty_1_N (
14624 val,
14625 0/*regparms*/,
14626 "x86g_dirtyhelper_RDTSC",
14627 &x86g_dirtyhelper_RDTSC,
14628 args
14629 );
sewardja5cbbdc2005-08-23 23:17:38 +000014630 /* execute the dirty call, dumping the result in val. */
14631 stmt( IRStmt_Dirty(d) );
14632 putIReg(4, R_EDX, unop(Iop_64HIto32, mkexpr(val)));
14633 putIReg(4, R_EAX, unop(Iop_64to32, mkexpr(val)));
14634 DIP("rdtsc\n");
14635 break;
sewardj4ed64292005-08-23 19:24:29 +000014636 }
sewardj77b86be2004-07-11 13:28:24 +000014637
sewardjb64821b2004-12-14 10:00:16 +000014638 /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
14639
14640 case 0xA1: /* POP %FS */
14641 dis_pop_segreg( R_FS, sz ); break;
14642 case 0xA9: /* POP %GS */
14643 dis_pop_segreg( R_GS, sz ); break;
14644
14645 case 0xA0: /* PUSH %FS */
14646 dis_push_segreg( R_FS, sz ); break;
14647 case 0xA8: /* PUSH %GS */
14648 dis_push_segreg( R_GS, sz ); break;
14649
sewardj77b86be2004-07-11 13:28:24 +000014650 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
14651 case 0x90:
14652 case 0x91:
14653 case 0x92: /* set-Bb/set-NAEb (jump below) */
14654 case 0x93: /* set-NBb/set-AEb (jump not below) */
14655 case 0x94: /* set-Zb/set-Eb (jump zero) */
14656 case 0x95: /* set-NZb/set-NEb (jump not zero) */
14657 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
14658 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
14659 case 0x98: /* set-Sb (jump negative) */
14660 case 0x99: /* set-Sb (jump not negative) */
14661 case 0x9A: /* set-P (jump parity even) */
14662 case 0x9B: /* set-NP (jump parity odd) */
14663 case 0x9C: /* set-Lb/set-NGEb (jump less) */
14664 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
14665 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
14666 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
sewardj5bd4d162004-11-10 13:02:48 +000014667 t1 = newTemp(Ity_I8);
sewardj2a9ad022004-11-25 02:46:58 +000014668 assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
sewardj77b86be2004-07-11 13:28:24 +000014669 modrm = getIByte(delta);
14670 if (epartIsReg(modrm)) {
14671 delta++;
sewardj5bd4d162004-11-10 13:02:48 +000014672 putIReg(1, eregOfRM(modrm), mkexpr(t1));
sewardj2a9ad022004-11-25 02:46:58 +000014673 DIP("set%s %s\n", name_X86Condcode(opc-0x90),
sewardj77b86be2004-07-11 13:28:24 +000014674 nameIReg(1,eregOfRM(modrm)));
14675 } else {
sewardj750f4072004-07-26 22:39:11 +000014676 addr = disAMode ( &alen, sorb, delta, dis_buf );
14677 delta += alen;
14678 storeLE( mkexpr(addr), mkexpr(t1) );
sewardj2a9ad022004-11-25 02:46:58 +000014679 DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +000014680 }
14681 break;
14682
sewardj180e8b32004-07-29 01:40:11 +000014683 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
14684
14685 case 0xA4: /* SHLDv imm8,Gv,Ev */
14686 modrm = getIByte(delta);
14687 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000014688 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj180e8b32004-07-29 01:40:11 +000014689 delta = dis_SHLRD_Gv_Ev (
14690 sorb, delta, modrm, sz,
14691 mkU8(getIByte(d32)), True, /* literal */
14692 dis_buf, True );
14693 break;
sewardja06e5562004-07-14 13:18:05 +000014694 case 0xA5: /* SHLDv %cl,Gv,Ev */
14695 modrm = getIByte(delta);
14696 delta = dis_SHLRD_Gv_Ev (
14697 sorb, delta, modrm, sz,
14698 getIReg(1,R_ECX), False, /* not literal */
14699 "%cl", True );
14700 break;
14701
sewardj68511542004-07-28 00:15:44 +000014702 case 0xAC: /* SHRDv imm8,Gv,Ev */
14703 modrm = getIByte(delta);
14704 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000014705 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj68511542004-07-28 00:15:44 +000014706 delta = dis_SHLRD_Gv_Ev (
14707 sorb, delta, modrm, sz,
14708 mkU8(getIByte(d32)), True, /* literal */
14709 dis_buf, False );
14710 break;
sewardja511afc2004-07-29 22:26:03 +000014711 case 0xAD: /* SHRDv %cl,Gv,Ev */
14712 modrm = getIByte(delta);
14713 delta = dis_SHLRD_Gv_Ev (
14714 sorb, delta, modrm, sz,
14715 getIReg(1,R_ECX), False, /* not literal */
14716 "%cl", False );
14717 break;
14718
sewardjf07ed032005-08-07 14:48:03 +000014719 /* =-=-=-=-=-=-=-=-=- SYSENTER -=-=-=-=-=-=-=-=-=-= */
14720
14721 case 0x34:
14722 /* Simple implementation needing a long explaination.
14723
14724 sysenter is a kind of syscall entry. The key thing here
14725 is that the return address is not known -- that is
14726 something that is beyond Vex's knowledge. So this IR
14727 forces a return to the scheduler, which can do what it
sewardj4fa325a2005-11-03 13:27:24 +000014728 likes to simulate the systenter, but it MUST set this
sewardjf07ed032005-08-07 14:48:03 +000014729 thread's guest_EIP field with the continuation address
14730 before resuming execution. If that doesn't happen, the
14731 thread will jump to address zero, which is probably
14732 fatal.
sewardje86310f2009-03-19 22:21:40 +000014733 */
14734
14735 /* Note where we are, so we can back up the guest to this
14736 point if the syscall needs to be restarted. */
14737 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
14738 mkU32(guest_EIP_curr_instr) ) );
sewardj4fa325a2005-11-03 13:27:24 +000014739 jmp_lit(Ijk_Sys_sysenter, 0/*bogus next EIP value*/);
sewardjf07ed032005-08-07 14:48:03 +000014740 dres.whatNext = Dis_StopHere;
14741 DIP("sysenter");
14742 break;
14743
sewardj464efa42004-11-19 22:17:29 +000014744 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
14745
sewardj0092e0d2006-03-06 13:35:42 +000014746 case 0xC0: { /* XADD Gb,Eb */
14747 Bool decodeOK;
sewardje9d8a262009-07-01 08:06:34 +000014748 delta = dis_xadd_G_E ( sorb, pfx_lock, 1, delta, &decodeOK );
sewardj0092e0d2006-03-06 13:35:42 +000014749 if (!decodeOK) goto decode_failure;
sewardj883b00b2004-09-11 09:30:24 +000014750 break;
sewardj0092e0d2006-03-06 13:35:42 +000014751 }
14752 case 0xC1: { /* XADD Gv,Ev */
14753 Bool decodeOK;
sewardje9d8a262009-07-01 08:06:34 +000014754 delta = dis_xadd_G_E ( sorb, pfx_lock, sz, delta, &decodeOK );
sewardj0092e0d2006-03-06 13:35:42 +000014755 if (!decodeOK) goto decode_failure;
14756 break;
14757 }
sewardj883b00b2004-09-11 09:30:24 +000014758
sewardjf13f37b2004-12-08 17:01:23 +000014759 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
sewardj464efa42004-11-19 22:17:29 +000014760
sewardj2b7a9202004-11-26 19:15:38 +000014761 case 0x71:
14762 case 0x72:
sewardj38a3f862005-01-13 15:06:51 +000014763 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardj2b7a9202004-11-26 19:15:38 +000014764
14765 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
14766 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj464efa42004-11-19 22:17:29 +000014767 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj2b7a9202004-11-26 19:15:38 +000014768 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +000014769
14770 case 0xFC:
14771 case 0xFD:
14772 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
14773
14774 case 0xEC:
14775 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
14776
14777 case 0xDC:
14778 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
14779
14780 case 0xF8:
14781 case 0xF9:
14782 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
14783
14784 case 0xE8:
14785 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
14786
14787 case 0xD8:
14788 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
14789
14790 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
14791 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
14792
sewardj4340dac2004-11-20 13:17:04 +000014793 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
14794
14795 case 0x74:
14796 case 0x75:
14797 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
14798
14799 case 0x64:
14800 case 0x65:
14801 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
14802
sewardj63ba4092004-11-21 12:30:18 +000014803 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
14804 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
14805 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
14806
14807 case 0x68:
14808 case 0x69:
14809 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
14810
14811 case 0x60:
14812 case 0x61:
14813 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
14814
14815 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
14816 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
14817 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
14818 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
14819
sewardj38a3f862005-01-13 15:06:51 +000014820 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000014821 case 0xF2:
sewardj38a3f862005-01-13 15:06:51 +000014822 case 0xF3:
sewardj8d14a592004-11-21 17:04:50 +000014823
sewardj38a3f862005-01-13 15:06:51 +000014824 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000014825 case 0xD2:
sewardj38a3f862005-01-13 15:06:51 +000014826 case 0xD3:
sewardj8d14a592004-11-21 17:04:50 +000014827
sewardj38a3f862005-01-13 15:06:51 +000014828 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
14829 case 0xE2:
sewardj464efa42004-11-19 22:17:29 +000014830 {
sewardj52d04912005-07-03 00:52:48 +000014831 Int delta0 = delta-1;
sewardj464efa42004-11-19 22:17:29 +000014832 Bool decode_OK = False;
sewardj38a3f862005-01-13 15:06:51 +000014833
14834 /* If sz==2 this is SSE, and we assume sse idec has
14835 already spotted those cases by now. */
14836 if (sz != 4)
14837 goto decode_failure;
14838
sewardj464efa42004-11-19 22:17:29 +000014839 delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
14840 if (!decode_OK) {
14841 delta = delta0;
14842 goto decode_failure;
14843 }
14844 break;
14845 }
14846
sewardj8d14a592004-11-21 17:04:50 +000014847 case 0x77: /* EMMS */
sewardj38a3f862005-01-13 15:06:51 +000014848 if (sz != 4)
14849 goto decode_failure;
sewardj4cb918d2004-12-03 19:43:31 +000014850 do_EMMS_preamble();
sewardj8d14a592004-11-21 17:04:50 +000014851 DIP("emms\n");
14852 break;
14853
sewardjb9dc2432010-06-07 16:22:22 +000014854 /* =-=-=-=-=-=-=-=-=- SGDT and SIDT =-=-=-=-=-=-=-=-=-=-= */
14855 case 0x01: /* 0F 01 /0 -- SGDT */
14856 /* 0F 01 /1 -- SIDT */
14857 {
14858 /* This is really revolting, but ... since each processor
14859 (core) only has one IDT and one GDT, just let the guest
14860 see it (pass-through semantics). I can't see any way to
14861 construct a faked-up value, so don't bother to try. */
14862 modrm = getUChar(delta);
14863 addr = disAMode ( &alen, sorb, delta, dis_buf );
14864 delta += alen;
14865 if (epartIsReg(modrm)) goto decode_failure;
14866 if (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)
14867 goto decode_failure;
14868 switch (gregOfRM(modrm)) {
14869 case 0: DIP("sgdt %s\n", dis_buf); break;
14870 case 1: DIP("sidt %s\n", dis_buf); break;
14871 default: vassert(0); /*NOTREACHED*/
14872 }
14873
14874 IRDirty* d = unsafeIRDirty_0_N (
14875 0/*regparms*/,
14876 "x86g_dirtyhelper_SxDT",
14877 &x86g_dirtyhelper_SxDT,
14878 mkIRExprVec_2( mkexpr(addr),
14879 mkU32(gregOfRM(modrm)) )
14880 );
14881 /* declare we're writing memory */
14882 d->mFx = Ifx_Write;
14883 d->mAddr = mkexpr(addr);
14884 d->mSize = 6;
14885 stmt( IRStmt_Dirty(d) );
14886 break;
14887 }
14888
sewardje87b4842004-07-10 12:23:30 +000014889 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
14890
14891 default:
14892 goto decode_failure;
14893 } /* switch (opc) for the 2-byte opcodes */
14894 goto decode_success;
14895 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +000014896
14897 /* ------------------------ ??? ------------------------ */
14898
14899 default:
sewardje87b4842004-07-10 12:23:30 +000014900 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +000014901 /* All decode failures end up here. */
sewardj52444cb2004-12-13 14:09:01 +000014902 vex_printf("vex x86->IR: unhandled instruction bytes: "
sewardjc9a65702004-07-07 16:32:57 +000014903 "0x%x 0x%x 0x%x 0x%x\n",
14904 (Int)getIByte(delta_start+0),
14905 (Int)getIByte(delta_start+1),
14906 (Int)getIByte(delta_start+2),
14907 (Int)getIByte(delta_start+3) );
sewardj52444cb2004-12-13 14:09:01 +000014908
sewardjb64821b2004-12-14 10:00:16 +000014909 /* Tell the dispatcher that this insn cannot be decoded, and so has
14910 not been executed, and (is currently) the next to be executed.
14911 EIP should be up-to-date since it made so at the start of each
14912 insn, but nevertheless be paranoid and update it again right
14913 now. */
sewardj9e6491a2005-07-02 19:24:10 +000014914 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr) ) );
14915 jmp_lit(Ijk_NoDecode, guest_EIP_curr_instr);
14916 dres.whatNext = Dis_StopHere;
14917 dres.len = 0;
sewardje9d8a262009-07-01 08:06:34 +000014918 /* We also need to say that a CAS is not expected now, regardless
14919 of what it might have been set to at the start of the function,
14920 since the IR that we've emitted just above (to synthesis a
14921 SIGILL) does not involve any CAS, and presumably no other IR has
14922 been emitted for this (non-decoded) insn. */
14923 *expect_CAS = False;
sewardj9e6491a2005-07-02 19:24:10 +000014924 return dres;
sewardj52444cb2004-12-13 14:09:01 +000014925
sewardjc9a65702004-07-07 16:32:57 +000014926 } /* switch (opc) for the main (primary) opcode switch. */
14927
sewardje87b4842004-07-10 12:23:30 +000014928 decode_success:
sewardjc9a65702004-07-07 16:32:57 +000014929 /* All decode successes end up here. */
14930 DIP("\n");
sewardj9e6491a2005-07-02 19:24:10 +000014931 dres.len = delta - delta_start;
14932 return dres;
sewardjc9a65702004-07-07 16:32:57 +000014933}
14934
14935#undef DIP
14936#undef DIS
14937
sewardj9e6491a2005-07-02 19:24:10 +000014938
14939/*------------------------------------------------------------*/
14940/*--- Top-level fn ---*/
14941/*------------------------------------------------------------*/
14942
14943/* Disassemble a single instruction into IR. The instruction
14944 is located in host memory at &guest_code[delta]. */
14945
sewardjdd40fdf2006-12-24 02:20:24 +000014946DisResult disInstr_X86 ( IRSB* irsb_IN,
sewardj9e6491a2005-07-02 19:24:10 +000014947 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +000014948 Bool (*resteerOkFn) ( void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +000014949 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +000014950 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000014951 UChar* guest_code_IN,
14952 Long delta,
14953 Addr64 guest_IP,
sewardja5f55da2006-04-30 23:37:32 +000014954 VexArch guest_arch,
sewardj9e6491a2005-07-02 19:24:10 +000014955 VexArchInfo* archinfo,
sewardjdd40fdf2006-12-24 02:20:24 +000014956 VexAbiInfo* abiinfo,
sewardj9e6491a2005-07-02 19:24:10 +000014957 Bool host_bigendian_IN )
14958{
sewardje9d8a262009-07-01 08:06:34 +000014959 Int i, x1, x2;
14960 Bool expect_CAS, has_CAS;
sewardj9e6491a2005-07-02 19:24:10 +000014961 DisResult dres;
14962
14963 /* Set globals (see top of this file) */
sewardja5f55da2006-04-30 23:37:32 +000014964 vassert(guest_arch == VexArchX86);
sewardj9e6491a2005-07-02 19:24:10 +000014965 guest_code = guest_code_IN;
sewardjdd40fdf2006-12-24 02:20:24 +000014966 irsb = irsb_IN;
sewardj9e6491a2005-07-02 19:24:10 +000014967 host_is_bigendian = host_bigendian_IN;
14968 guest_EIP_curr_instr = (Addr32)guest_IP;
14969 guest_EIP_bbstart = (Addr32)toUInt(guest_IP - delta);
14970
sewardje9d8a262009-07-01 08:06:34 +000014971 x1 = irsb_IN->stmts_used;
14972 expect_CAS = False;
14973 dres = disInstr_X86_WRK ( &expect_CAS, put_IP, resteerOkFn,
sewardj984d9b12010-01-15 10:53:21 +000014974 resteerCisOk,
sewardje9d8a262009-07-01 08:06:34 +000014975 callback_opaque, delta, archinfo );
14976 x2 = irsb_IN->stmts_used;
14977 vassert(x2 >= x1);
14978
14979 /* See comment at the top of disInstr_X86_WRK for meaning of
14980 expect_CAS. Here, we (sanity-)check for the presence/absence of
14981 IRCAS as directed by the returned expect_CAS value. */
14982 has_CAS = False;
14983 for (i = x1; i < x2; i++) {
14984 if (irsb_IN->stmts[i]->tag == Ist_CAS)
14985 has_CAS = True;
14986 }
14987
14988 if (expect_CAS != has_CAS) {
14989 /* inconsistency detected. re-disassemble the instruction so as
14990 to generate a useful error message; then assert. */
14991 vex_traceflags |= VEX_TRACE_FE;
14992 dres = disInstr_X86_WRK ( &expect_CAS, put_IP, resteerOkFn,
sewardj984d9b12010-01-15 10:53:21 +000014993 resteerCisOk,
sewardje9d8a262009-07-01 08:06:34 +000014994 callback_opaque, delta, archinfo );
14995 for (i = x1; i < x2; i++) {
14996 vex_printf("\t\t");
14997 ppIRStmt(irsb_IN->stmts[i]);
14998 vex_printf("\n");
14999 }
15000 /* Failure of this assertion is serious and denotes a bug in
15001 disInstr. */
15002 vpanic("disInstr_X86: inconsistency in LOCK prefix handling");
15003 }
sewardj9e6491a2005-07-02 19:24:10 +000015004
15005 return dres;
15006}
15007
15008
sewardjc9a65702004-07-07 16:32:57 +000015009/*--------------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +000015010/*--- end guest_x86_toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +000015011/*--------------------------------------------------------------------*/