blob: 1d527326b9872076275739fb1ed5358501729564 [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. */
sewardj17b0e212011-03-26 07:28:51 +00001001 stmt( IRStmt_Put( OFFB_CC_NDEP,
1002 IRExpr_Mux0X( mkexpr(guard),
1003 IRExpr_Get(OFFB_CC_NDEP,Ity_I32),
1004 mkU32(0) )));
sewardj0611d802004-07-11 02:37:54 +00001005}
1006
1007
sewardj2a2ba8b2004-11-08 13:14:06 +00001008/* For the inc/dec case, we store in DEP1 the result value and in NDEP
sewardj948d48b2004-11-05 19:49:09 +00001009 the former value of the carry flag, which unfortunately we have to
1010 compute. */
sewardj0611d802004-07-11 02:37:54 +00001011
sewardj948d48b2004-11-05 19:49:09 +00001012static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
sewardj0611d802004-07-11 02:37:54 +00001013{
sewardj2a9ad022004-11-25 02:46:58 +00001014 Int ccOp = inc ? X86G_CC_OP_INCB : X86G_CC_OP_DECB;
sewardj0611d802004-07-11 02:37:54 +00001015
1016 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
1017 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
1018
1019 /* This has to come first, because calculating the C flag
sewardj2a2ba8b2004-11-08 13:14:06 +00001020 may require reading all four thunk fields. */
sewardj2a9ad022004-11-25 02:46:58 +00001021 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_x86g_calculate_eflags_c()) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001022 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
sewardj478646f2008-05-01 20:13:04 +00001023 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(res))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001024 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardj0611d802004-07-11 02:37:54 +00001025}
1026
1027
sewardj2a2ba8b2004-11-08 13:14:06 +00001028/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1029 two arguments. */
sewardjcf780b42004-07-13 18:42:17 +00001030
1031static
sewardj2a2ba8b2004-11-08 13:14:06 +00001032void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
sewardjcf780b42004-07-13 18:42:17 +00001033{
1034 switch (ty) {
sewardj2a2ba8b2004-11-08 13:14:06 +00001035 case Ity_I8:
1036 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
1037 break;
1038 case Ity_I16:
1039 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
1040 break;
1041 case Ity_I32:
1042 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
1043 break;
1044 default:
1045 vpanic("setFlags_MUL(x86)");
sewardjcf780b42004-07-13 18:42:17 +00001046 }
sewardj2a2ba8b2004-11-08 13:14:06 +00001047 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
1048 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
sewardja3b7e3a2005-04-05 01:54:19 +00001049 /* Set NDEP even though it isn't used. This makes redundant-PUT
1050 elimination of previous stores to this field work better. */
1051 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjcf780b42004-07-13 18:42:17 +00001052}
1053
1054
sewardj3af115f2004-07-14 02:46:52 +00001055/* -------------- Condition codes. -------------- */
1056
sewardje87b4842004-07-10 12:23:30 +00001057/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +00001058
sewardj2d49b432005-02-01 00:37:06 +00001059static HChar* name_X86Condcode ( X86Condcode cond )
sewardje87b4842004-07-10 12:23:30 +00001060{
1061 switch (cond) {
sewardj2a9ad022004-11-25 02:46:58 +00001062 case X86CondO: return "o";
1063 case X86CondNO: return "no";
1064 case X86CondB: return "b";
1065 case X86CondNB: return "nb";
1066 case X86CondZ: return "z";
1067 case X86CondNZ: return "nz";
1068 case X86CondBE: return "be";
1069 case X86CondNBE: return "nbe";
1070 case X86CondS: return "s";
1071 case X86CondNS: return "ns";
1072 case X86CondP: return "p";
1073 case X86CondNP: return "np";
1074 case X86CondL: return "l";
1075 case X86CondNL: return "nl";
1076 case X86CondLE: return "le";
1077 case X86CondNLE: return "nle";
1078 case X86CondAlways: return "ALWAYS";
1079 default: vpanic("name_X86Condcode");
sewardje87b4842004-07-10 12:23:30 +00001080 }
1081}
1082
sewardj2a9ad022004-11-25 02:46:58 +00001083static
1084X86Condcode positiveIse_X86Condcode ( X86Condcode cond,
sewardjdbf550c2005-01-24 11:54:11 +00001085 Bool* needInvert )
sewardje87b4842004-07-10 12:23:30 +00001086{
sewardj2a9ad022004-11-25 02:46:58 +00001087 vassert(cond >= X86CondO && cond <= X86CondNLE);
sewardje87b4842004-07-10 12:23:30 +00001088 if (cond & 1) {
1089 *needInvert = True;
1090 return cond-1;
1091 } else {
1092 *needInvert = False;
1093 return cond;
1094 }
1095}
1096
1097
sewardj3af115f2004-07-14 02:46:52 +00001098/* -------------- Helpers for ADD/SUB with carry. -------------- */
1099
sewardj948d48b2004-11-05 19:49:09 +00001100/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001101 appropriately.
sewardje9d8a262009-07-01 08:06:34 +00001102
1103 Optionally, generate a store for the 'tres' value. This can either
1104 be a normal store, or it can be a cas-with-possible-failure style
1105 store:
1106
1107 if taddr is IRTemp_INVALID, then no store is generated.
1108
1109 if taddr is not IRTemp_INVALID, then a store (using taddr as
1110 the address) is generated:
1111
1112 if texpVal is IRTemp_INVALID then a normal store is
1113 generated, and restart_point must be zero (it is irrelevant).
1114
1115 if texpVal is not IRTemp_INVALID then a cas-style store is
1116 generated. texpVal is the expected value, restart_point
1117 is the restart point if the store fails, and texpVal must
1118 have the same type as tres.
sewardj3af115f2004-07-14 02:46:52 +00001119*/
1120static void helper_ADC ( Int sz,
sewardje9d8a262009-07-01 08:06:34 +00001121 IRTemp tres, IRTemp ta1, IRTemp ta2,
1122 /* info about optional store: */
1123 IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
sewardj3af115f2004-07-14 02:46:52 +00001124{
1125 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001126 IRType ty = szToITy(sz);
1127 IRTemp oldc = newTemp(Ity_I32);
1128 IRTemp oldcn = newTemp(ty);
1129 IROp plus = mkSizedOp(ty, Iop_Add8);
1130 IROp xor = mkSizedOp(ty, Iop_Xor8);
sewardja2384712004-07-29 14:36:40 +00001131
sewardje9d8a262009-07-01 08:06:34 +00001132 vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
sewardja2384712004-07-29 14:36:40 +00001133 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001134 thunkOp = sz==4 ? X86G_CC_OP_ADCL
1135 : (sz==2 ? X86G_CC_OP_ADCW : X86G_CC_OP_ADCB);
sewardj3af115f2004-07-14 02:46:52 +00001136
sewardj2a2ba8b2004-11-08 13:14:06 +00001137 /* oldc = old carry flag, 0 or 1 */
1138 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001139 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001140 mkU32(1)) );
sewardj3af115f2004-07-14 02:46:52 +00001141
sewardj2a2ba8b2004-11-08 13:14:06 +00001142 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1143
1144 assign( tres, binop(plus,
1145 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1146 mkexpr(oldcn)) );
1147
sewardje9d8a262009-07-01 08:06:34 +00001148 /* Possibly generate a store of 'tres' to 'taddr'. See comment at
1149 start of this function. */
1150 if (taddr != IRTemp_INVALID) {
1151 if (texpVal == IRTemp_INVALID) {
1152 vassert(restart_point == 0);
1153 storeLE( mkexpr(taddr), mkexpr(tres) );
1154 } else {
1155 vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1156 /* .. and hence 'texpVal' has the same type as 'tres'. */
1157 casLE( mkexpr(taddr),
1158 mkexpr(texpVal), mkexpr(tres), restart_point );
1159 }
1160 }
1161
sewardj2a2ba8b2004-11-08 13:14:06 +00001162 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
sewardj3b3eacd2005-08-24 10:01:36 +00001163 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1)) ));
1164 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
1165 mkexpr(oldcn)) )) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001166 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardj3af115f2004-07-14 02:46:52 +00001167}
1168
1169
sewardj948d48b2004-11-05 19:49:09 +00001170/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
sewardje9d8a262009-07-01 08:06:34 +00001171 appropriately. As with helper_ADC, possibly generate a store of
1172 the result -- see comments on helper_ADC for details.
sewardjcaca9d02004-07-28 07:11:32 +00001173*/
1174static void helper_SBB ( Int sz,
sewardje9d8a262009-07-01 08:06:34 +00001175 IRTemp tres, IRTemp ta1, IRTemp ta2,
1176 /* info about optional store: */
1177 IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
sewardjcaca9d02004-07-28 07:11:32 +00001178{
1179 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001180 IRType ty = szToITy(sz);
1181 IRTemp oldc = newTemp(Ity_I32);
1182 IRTemp oldcn = newTemp(ty);
1183 IROp minus = mkSizedOp(ty, Iop_Sub8);
1184 IROp xor = mkSizedOp(ty, Iop_Xor8);
1185
sewardje9d8a262009-07-01 08:06:34 +00001186 vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
sewardj2a2ba8b2004-11-08 13:14:06 +00001187 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001188 thunkOp = sz==4 ? X86G_CC_OP_SBBL
1189 : (sz==2 ? X86G_CC_OP_SBBW : X86G_CC_OP_SBBB);
sewardjcaca9d02004-07-28 07:11:32 +00001190
1191 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +00001192 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001193 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001194 mkU32(1)) );
sewardjcaca9d02004-07-28 07:11:32 +00001195
sewardj2a2ba8b2004-11-08 13:14:06 +00001196 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
sewardja2384712004-07-29 14:36:40 +00001197
sewardj2a2ba8b2004-11-08 13:14:06 +00001198 assign( tres, binop(minus,
1199 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1200 mkexpr(oldcn)) );
sewardjcaca9d02004-07-28 07:11:32 +00001201
sewardje9d8a262009-07-01 08:06:34 +00001202 /* Possibly generate a store of 'tres' to 'taddr'. See comment at
1203 start of this function. */
1204 if (taddr != IRTemp_INVALID) {
1205 if (texpVal == IRTemp_INVALID) {
1206 vassert(restart_point == 0);
1207 storeLE( mkexpr(taddr), mkexpr(tres) );
1208 } else {
1209 vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1210 /* .. and hence 'texpVal' has the same type as 'tres'. */
1211 casLE( mkexpr(taddr),
1212 mkexpr(texpVal), mkexpr(tres), restart_point );
1213 }
1214 }
1215
sewardj2a2ba8b2004-11-08 13:14:06 +00001216 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
sewardj3b3eacd2005-08-24 10:01:36 +00001217 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1) )) );
1218 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
1219 mkexpr(oldcn)) )) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001220 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardjcaca9d02004-07-28 07:11:32 +00001221}
1222
1223
sewardj7dd2eb22005-01-05 10:38:54 +00001224/* -------------- Helpers for disassembly printing. -------------- */
sewardj41f43bc2004-07-08 14:23:22 +00001225
sewardjc9a43662004-11-30 18:51:59 +00001226static HChar* nameGrp1 ( Int opc_aux )
sewardj41f43bc2004-07-08 14:23:22 +00001227{
sewardjc9a43662004-11-30 18:51:59 +00001228 static HChar* grp1_names[8]
sewardj41f43bc2004-07-08 14:23:22 +00001229 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1230 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1231 return grp1_names[opc_aux];
1232}
1233
sewardjc9a43662004-11-30 18:51:59 +00001234static HChar* nameGrp2 ( Int opc_aux )
sewardje90ad6a2004-07-10 19:02:10 +00001235{
sewardjc9a43662004-11-30 18:51:59 +00001236 static HChar* grp2_names[8]
sewardje90ad6a2004-07-10 19:02:10 +00001237 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +00001238 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +00001239 return grp2_names[opc_aux];
1240}
1241
sewardjc9a43662004-11-30 18:51:59 +00001242static HChar* nameGrp4 ( Int opc_aux )
sewardjc2ac51e2004-07-12 01:03:26 +00001243{
sewardjc9a43662004-11-30 18:51:59 +00001244 static HChar* grp4_names[8]
sewardjc2ac51e2004-07-12 01:03:26 +00001245 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1246 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1247 return grp4_names[opc_aux];
1248}
sewardj0611d802004-07-11 02:37:54 +00001249
sewardjc9a43662004-11-30 18:51:59 +00001250static HChar* nameGrp5 ( Int opc_aux )
sewardj0611d802004-07-11 02:37:54 +00001251{
sewardjc9a43662004-11-30 18:51:59 +00001252 static HChar* grp5_names[8]
sewardj0611d802004-07-11 02:37:54 +00001253 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1254 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1255 return grp5_names[opc_aux];
1256}
1257
sewardj490ad382005-03-13 17:25:53 +00001258static HChar* nameGrp8 ( Int opc_aux )
1259{
1260 static HChar* grp8_names[8]
1261 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1262 if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(x86)");
1263 return grp8_names[opc_aux];
1264}
sewardjc9a65702004-07-07 16:32:57 +00001265
sewardjc9a43662004-11-30 18:51:59 +00001266static HChar* nameIReg ( Int size, Int reg )
sewardjc9a65702004-07-07 16:32:57 +00001267{
sewardjc9a43662004-11-30 18:51:59 +00001268 static HChar* ireg32_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001269 = { "%eax", "%ecx", "%edx", "%ebx",
1270 "%esp", "%ebp", "%esi", "%edi" };
sewardjc9a43662004-11-30 18:51:59 +00001271 static HChar* ireg16_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001272 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
sewardjc9a43662004-11-30 18:51:59 +00001273 static HChar* ireg8_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001274 = { "%al", "%cl", "%dl", "%bl",
1275 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1276 if (reg < 0 || reg > 7) goto bad;
1277 switch (size) {
1278 case 4: return ireg32_names[reg];
1279 case 2: return ireg16_names[reg];
1280 case 1: return ireg8_names[reg];
1281 }
1282 bad:
1283 vpanic("nameIReg(X86)");
1284 return NULL; /*notreached*/
1285}
1286
sewardjc9a43662004-11-30 18:51:59 +00001287static HChar* nameSReg ( UInt sreg )
sewardj063f02f2004-10-20 12:36:12 +00001288{
1289 switch (sreg) {
1290 case R_ES: return "%es";
1291 case R_CS: return "%cs";
1292 case R_SS: return "%ss";
1293 case R_DS: return "%ds";
1294 case R_FS: return "%fs";
1295 case R_GS: return "%gs";
1296 default: vpanic("nameSReg(x86)");
1297 }
1298}
1299
sewardjc9a43662004-11-30 18:51:59 +00001300static HChar* nameMMXReg ( Int mmxreg )
sewardj464efa42004-11-19 22:17:29 +00001301{
sewardjc9a43662004-11-30 18:51:59 +00001302 static HChar* mmx_names[8]
sewardj464efa42004-11-19 22:17:29 +00001303 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1304 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1305 return mmx_names[mmxreg];
1306}
1307
sewardjc9a43662004-11-30 18:51:59 +00001308static HChar* nameXMMReg ( Int xmmreg )
1309{
1310 static HChar* xmm_names[8]
1311 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1312 "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1313 if (xmmreg < 0 || xmmreg > 7) vpanic("name_of_xmm_reg");
1314 return xmm_names[xmmreg];
1315}
sewardj464efa42004-11-19 22:17:29 +00001316
sewardj2d49b432005-02-01 00:37:06 +00001317static HChar* nameMMXGran ( Int gran )
sewardj464efa42004-11-19 22:17:29 +00001318{
1319 switch (gran) {
1320 case 0: return "b";
1321 case 1: return "w";
1322 case 2: return "d";
1323 case 3: return "q";
1324 default: vpanic("nameMMXGran(x86,guest)");
1325 }
1326}
sewardjc9a65702004-07-07 16:32:57 +00001327
sewardj2d49b432005-02-01 00:37:06 +00001328static HChar nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001329{
1330 switch (size) {
1331 case 4: return 'l';
1332 case 2: return 'w';
1333 case 1: return 'b';
1334 default: vpanic("nameISize(x86)");
1335 }
1336}
1337
sewardjd1061ab2004-07-08 01:45:30 +00001338
1339/*------------------------------------------------------------*/
1340/*--- JMP helpers ---*/
1341/*------------------------------------------------------------*/
1342
sewardj78c19df2004-07-12 22:49:27 +00001343static void jmp_lit( IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001344{
sewardjdd40fdf2006-12-24 02:20:24 +00001345 irsb->next = mkU32(d32);
1346 irsb->jumpkind = kind;
sewardjd1061ab2004-07-08 01:45:30 +00001347}
1348
sewardj78c19df2004-07-12 22:49:27 +00001349static void jmp_treg( IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001350{
sewardjdd40fdf2006-12-24 02:20:24 +00001351 irsb->next = mkexpr(t);
1352 irsb->jumpkind = kind;
sewardje05c42c2004-07-08 20:25:10 +00001353}
sewardje87b4842004-07-10 12:23:30 +00001354
sewardj2a9ad022004-11-25 02:46:58 +00001355static
1356void jcc_01( X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001357{
sewardj2a9ad022004-11-25 02:46:58 +00001358 Bool invert;
1359 X86Condcode condPos;
1360 condPos = positiveIse_X86Condcode ( cond, &invert );
sewardje87b4842004-07-10 12:23:30 +00001361 if (invert) {
sewardj2a9ad022004-11-25 02:46:58 +00001362 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001363 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001364 IRConst_U32(d32_false) ) );
sewardjdd40fdf2006-12-24 02:20:24 +00001365 irsb->next = mkU32(d32_true);
1366 irsb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001367 } else {
sewardj2a9ad022004-11-25 02:46:58 +00001368 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001369 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001370 IRConst_U32(d32_true) ) );
sewardjdd40fdf2006-12-24 02:20:24 +00001371 irsb->next = mkU32(d32_false);
1372 irsb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001373 }
1374}
sewardjc9a65702004-07-07 16:32:57 +00001375
1376
sewardjd1061ab2004-07-08 01:45:30 +00001377/*------------------------------------------------------------*/
1378/*--- Disassembling addressing modes ---*/
1379/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001380
sewardjd1061ab2004-07-08 01:45:30 +00001381static
sewardj2d49b432005-02-01 00:37:06 +00001382HChar* sorbTxt ( UChar sorb )
sewardjd1061ab2004-07-08 01:45:30 +00001383{
1384 switch (sorb) {
1385 case 0: return ""; /* no override */
1386 case 0x3E: return "%ds";
1387 case 0x26: return "%es:";
1388 case 0x64: return "%fs:";
1389 case 0x65: return "%gs:";
sewardj7df596b2004-12-06 14:29:12 +00001390 default: vpanic("sorbTxt(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001391 }
1392}
1393
1394
sewardj7df596b2004-12-06 14:29:12 +00001395/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
1396 linear address by adding any required segment override as indicated
1397 by sorb. */
sewardjd1061ab2004-07-08 01:45:30 +00001398static
1399IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1400{
sewardj3bd6f3e2004-12-13 10:48:19 +00001401 Int sreg;
1402 IRType hWordTy;
1403 IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
sewardjd1061ab2004-07-08 01:45:30 +00001404
1405 if (sorb == 0)
1406 /* the common case - no override */
1407 return virtual;
1408
sewardjd1061ab2004-07-08 01:45:30 +00001409 switch (sorb) {
1410 case 0x3E: sreg = R_DS; break;
1411 case 0x26: sreg = R_ES; break;
1412 case 0x64: sreg = R_FS; break;
1413 case 0x65: sreg = R_GS; break;
sewardj7df596b2004-12-06 14:29:12 +00001414 default: vpanic("handleSegOverride(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001415 }
1416
sewardj3bd6f3e2004-12-13 10:48:19 +00001417 hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
sewardjd1061ab2004-07-08 01:45:30 +00001418
sewardj3bd6f3e2004-12-13 10:48:19 +00001419 seg_selector = newTemp(Ity_I32);
1420 ldt_ptr = newTemp(hWordTy);
1421 gdt_ptr = newTemp(hWordTy);
1422 r64 = newTemp(Ity_I64);
sewardjd1061ab2004-07-08 01:45:30 +00001423
sewardj3bd6f3e2004-12-13 10:48:19 +00001424 assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
1425 assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
1426 assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
sewardj7df596b2004-12-06 14:29:12 +00001427
sewardj3bd6f3e2004-12-13 10:48:19 +00001428 /*
1429 Call this to do the translation and limit checks:
1430 ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
1431 UInt seg_selector, UInt virtual_addr )
1432 */
1433 assign(
1434 r64,
1435 mkIRExprCCall(
1436 Ity_I64,
1437 0/*regparms*/,
1438 "x86g_use_seg_selector",
1439 &x86g_use_seg_selector,
1440 mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
1441 mkexpr(seg_selector), virtual)
1442 )
1443 );
sewardj7df596b2004-12-06 14:29:12 +00001444
sewardj52444cb2004-12-13 14:09:01 +00001445 /* If the high 32 of the result are non-zero, there was a
1446 failure in address translation. In which case, make a
1447 quick exit.
1448 */
1449 stmt(
1450 IRStmt_Exit(
1451 binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
1452 Ijk_MapFail,
sewardj9e6491a2005-07-02 19:24:10 +00001453 IRConst_U32( guest_EIP_curr_instr )
sewardj52444cb2004-12-13 14:09:01 +00001454 )
1455 );
1456
1457 /* otherwise, here's the translated result. */
sewardj3bd6f3e2004-12-13 10:48:19 +00001458 return unop(Iop_64to32, mkexpr(r64));
sewardjd1061ab2004-07-08 01:45:30 +00001459}
1460
1461
1462/* Generate IR to calculate an address indicated by a ModRM and
1463 following SIB bytes. The expression, and the number of bytes in
1464 the address mode, are returned. Note that this fn should not be
1465 called if the R/M part of the address denotes a register instead of
1466 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001467 placed in buf.
1468
1469 The computed address is stored in a new tempreg, and the
1470 identity of the tempreg is returned. */
1471
1472static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1473{
1474 IRTemp tmp = newTemp(Ity_I32);
1475 assign( tmp, addr32 );
1476 return tmp;
1477}
sewardjd1061ab2004-07-08 01:45:30 +00001478
1479static
sewardj52d04912005-07-03 00:52:48 +00001480IRTemp disAMode ( Int* len, UChar sorb, Int delta, HChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001481{
1482 UChar mod_reg_rm = getIByte(delta);
1483 delta++;
1484
sewardj9ee82862004-12-14 01:16:59 +00001485 buf[0] = (UChar)0;
1486
sewardjd1061ab2004-07-08 01:45:30 +00001487 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1488 jump table seems a bit excessive.
1489 */
sewardj9b45b482005-02-07 01:42:18 +00001490 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1491 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1492 /* is now XX0XXYYY */
1493 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001494 switch (mod_reg_rm) {
1495
1496 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1497 --> GET %reg, t
1498 */
1499 case 0x00: case 0x01: case 0x02: case 0x03:
1500 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1501 { UChar rm = mod_reg_rm;
1502 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1503 *len = 1;
sewardj5bd4d162004-11-10 13:02:48 +00001504 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001505 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001506 }
1507
1508 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1509 --> GET %reg, t ; ADDL d8, t
1510 */
1511 case 0x08: case 0x09: case 0x0A: case 0x0B:
1512 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj9b45b482005-02-07 01:42:18 +00001513 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001514 UInt d = getSDisp8(delta);
sewardj2d49b432005-02-01 00:37:06 +00001515 DIS(buf, "%s%d(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001516 *len = 2;
1517 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001518 handleSegOverride(sorb,
1519 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001520 }
1521
1522 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1523 --> GET %reg, t ; ADDL d8, t
1524 */
1525 case 0x10: case 0x11: case 0x12: case 0x13:
1526 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj9b45b482005-02-07 01:42:18 +00001527 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001528 UInt d = getUDisp32(delta);
sewardj2d49b432005-02-01 00:37:06 +00001529 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001530 *len = 5;
1531 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001532 handleSegOverride(sorb,
1533 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001534 }
1535
1536 /* a register, %eax .. %edi. This shouldn't happen. */
1537 case 0x18: case 0x19: case 0x1A: case 0x1B:
1538 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1539 vpanic("disAMode(x86): not an addr!");
1540
1541 /* a 32-bit literal address
1542 --> MOV d32, tmp
1543 */
1544 case 0x05:
1545 { UInt d = getUDisp32(delta);
1546 *len = 5;
1547 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001548 return disAMode_copy2tmp(
1549 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001550 }
1551
1552 case 0x04: {
1553 /* SIB, with no displacement. Special cases:
1554 -- %esp cannot act as an index value.
1555 If index_r indicates %esp, zero is used for the index.
1556 -- when mod is zero and base indicates EBP, base is instead
1557 a 32-bit literal.
1558 It's all madness, I tell you. Extract %index, %base and
1559 scale from the SIB byte. The value denoted is then:
1560 | %index == %ESP && %base == %EBP
1561 = d32 following SIB byte
1562 | %index == %ESP && %base != %EBP
1563 = %base
1564 | %index != %ESP && %base == %EBP
1565 = d32 following SIB byte + (%index << scale)
1566 | %index != %ESP && %base != %ESP
1567 = %base + (%index << scale)
1568
1569 What happens to the souls of CPU architects who dream up such
1570 horrendous schemes, do you suppose?
1571 */
1572 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001573 UChar scale = toUChar((sib >> 6) & 3);
1574 UChar index_r = toUChar((sib >> 3) & 7);
1575 UChar base_r = toUChar(sib & 7);
sewardj5bd4d162004-11-10 13:02:48 +00001576 delta++;
sewardjd1061ab2004-07-08 01:45:30 +00001577
1578 if (index_r != R_ESP && base_r != R_EBP) {
1579 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1580 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001581 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001582 return
1583 disAMode_copy2tmp(
sewardj5bd4d162004-11-10 13:02:48 +00001584 handleSegOverride(sorb,
1585 binop(Iop_Add32,
sewardjd1061ab2004-07-08 01:45:30 +00001586 getIReg(4,base_r),
1587 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001588 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001589 }
1590
1591 if (index_r != R_ESP && base_r == R_EBP) {
1592 UInt d = getUDisp32(delta);
1593 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1594 nameIReg(4,index_r), 1<<scale);
1595 *len = 6;
1596 return
sewardj940e8c92004-07-11 16:53:24 +00001597 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001598 handleSegOverride(sorb,
sewardj5bd4d162004-11-10 13:02:48 +00001599 binop(Iop_Add32,
1600 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001601 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001602 }
1603
1604 if (index_r == R_ESP && base_r != R_EBP) {
1605 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001606 *len = 2;
1607 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001608 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001609 }
1610
1611 if (index_r == R_ESP && base_r == R_EBP) {
1612 UInt d = getUDisp32(delta);
sewardj9c3b25a2007-04-05 15:06:56 +00001613 DIS(buf, "%s0x%x(,,)", sorbTxt(sorb), d);
sewardj5bd4d162004-11-10 13:02:48 +00001614 *len = 6;
sewardj5bd4d162004-11-10 13:02:48 +00001615 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001616 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001617 }
sewardjba89f4c2005-04-07 17:31:27 +00001618 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001619 vassert(0);
1620 }
1621
1622 /* SIB, with 8-bit displacement. Special cases:
1623 -- %esp cannot act as an index value.
1624 If index_r indicates %esp, zero is used for the index.
1625 Denoted value is:
1626 | %index == %ESP
1627 = d8 + %base
1628 | %index != %ESP
1629 = d8 + %base + (%index << scale)
1630 */
1631 case 0x0C: {
1632 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001633 UChar scale = toUChar((sib >> 6) & 3);
1634 UChar index_r = toUChar((sib >> 3) & 7);
1635 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001636 UInt d = getSDisp8(delta+1);
1637
1638 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001639 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1640 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001641 *len = 3;
1642 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001643 handleSegOverride(sorb,
1644 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001645 } else {
sewardj2d49b432005-02-01 00:37:06 +00001646 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
sewardjd1061ab2004-07-08 01:45:30 +00001647 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001648 *len = 3;
1649 return
sewardj940e8c92004-07-11 16:53:24 +00001650 disAMode_copy2tmp(
1651 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001652 binop(Iop_Add32,
1653 binop(Iop_Add32,
1654 getIReg(4,base_r),
1655 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001656 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001657 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001658 }
sewardjba89f4c2005-04-07 17:31:27 +00001659 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001660 vassert(0);
1661 }
1662
1663 /* SIB, with 32-bit displacement. Special cases:
1664 -- %esp cannot act as an index value.
1665 If index_r indicates %esp, zero is used for the index.
1666 Denoted value is:
1667 | %index == %ESP
1668 = d32 + %base
1669 | %index != %ESP
1670 = d32 + %base + (%index << scale)
1671 */
1672 case 0x14: {
1673 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001674 UChar scale = toUChar((sib >> 6) & 3);
1675 UChar index_r = toUChar((sib >> 3) & 7);
1676 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001677 UInt d = getUDisp32(delta+1);
1678
1679 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001680 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1681 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001682 *len = 6;
1683 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001684 handleSegOverride(sorb,
1685 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001686 } else {
sewardj2d49b432005-02-01 00:37:06 +00001687 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1688 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001689 *len = 6;
1690 return
sewardj940e8c92004-07-11 16:53:24 +00001691 disAMode_copy2tmp(
1692 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001693 binop(Iop_Add32,
1694 binop(Iop_Add32,
1695 getIReg(4,base_r),
1696 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001697 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001698 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001699 }
sewardjba89f4c2005-04-07 17:31:27 +00001700 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001701 vassert(0);
1702 }
1703
1704 default:
1705 vpanic("disAMode(x86)");
1706 return 0; /*notreached*/
1707 }
1708}
1709
1710
1711/* Figure out the number of (insn-stream) bytes constituting the amode
1712 beginning at delta. Is useful for getting hold of literals beyond
1713 the end of the amode before it has been disassembled. */
1714
sewardj52d04912005-07-03 00:52:48 +00001715static UInt lengthAMode ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +00001716{
1717 UChar mod_reg_rm = getIByte(delta); delta++;
1718
1719 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1720 jump table seems a bit excessive.
1721 */
1722 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj9b45b482005-02-07 01:42:18 +00001723 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1724 /* is now XX0XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001725 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1726 switch (mod_reg_rm) {
1727
1728 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1729 case 0x00: case 0x01: case 0x02: case 0x03:
1730 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1731 return 1;
1732
1733 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1734 case 0x08: case 0x09: case 0x0A: case 0x0B:
1735 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1736 return 2;
1737
1738 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1739 case 0x10: case 0x11: case 0x12: case 0x13:
1740 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1741 return 5;
1742
1743 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1744 case 0x18: case 0x19: case 0x1A: case 0x1B:
1745 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1746 return 1;
1747
1748 /* a 32-bit literal address. */
1749 case 0x05: return 5;
1750
1751 /* SIB, no displacement. */
1752 case 0x04: {
1753 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001754 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001755 if (base_r == R_EBP) return 6; else return 2;
1756 }
1757 /* SIB, with 8-bit displacement. */
1758 case 0x0C: return 3;
1759
1760 /* SIB, with 32-bit displacement. */
1761 case 0x14: return 6;
1762
1763 default:
1764 vpanic("lengthAMode");
1765 return 0; /*notreached*/
1766 }
1767}
1768
1769/*------------------------------------------------------------*/
1770/*--- Disassembling common idioms ---*/
1771/*------------------------------------------------------------*/
1772
sewardje87b4842004-07-10 12:23:30 +00001773/* Handle binary integer instructions of the form
1774 op E, G meaning
1775 op reg-or-mem, reg
1776 Is passed the a ptr to the modRM byte, the actual operation, and the
1777 data size. Returns the address advanced completely over this
1778 instruction.
1779
1780 E(src) is reg-or-mem
1781 G(dst) is reg.
1782
1783 If E is reg, --> GET %G, tmp
1784 OP %E, tmp
1785 PUT tmp, %G
1786
1787 If E is mem and OP is not reversible,
1788 --> (getAddr E) -> tmpa
1789 LD (tmpa), tmpa
1790 GET %G, tmp2
1791 OP tmpa, tmp2
1792 PUT tmp2, %G
1793
1794 If E is mem and OP is reversible
1795 --> (getAddr E) -> tmpa
1796 LD (tmpa), tmpa
1797 OP %G, tmpa
1798 PUT tmpa, %G
1799*/
1800static
1801UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001802 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001803 IROp op8,
1804 Bool keep,
1805 Int size,
sewardj52d04912005-07-03 00:52:48 +00001806 Int delta0,
sewardj2d49b432005-02-01 00:37:06 +00001807 HChar* t_x86opc )
sewardje87b4842004-07-10 12:23:30 +00001808{
sewardjc9a43662004-11-30 18:51:59 +00001809 HChar dis_buf[50];
sewardj9334b0f2004-07-10 22:43:54 +00001810 Int len;
sewardje87b4842004-07-10 12:23:30 +00001811 IRType ty = szToITy(size);
1812 IRTemp dst1 = newTemp(ty);
1813 IRTemp src = newTemp(ty);
1814 IRTemp dst0 = newTemp(ty);
1815 UChar rm = getUChar(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001816 IRTemp addr = IRTemp_INVALID;
sewardje87b4842004-07-10 12:23:30 +00001817
sewardj180e8b32004-07-29 01:40:11 +00001818 /* addSubCarry == True indicates the intended operation is
1819 add-with-carry or subtract-with-borrow. */
1820 if (addSubCarry) {
1821 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1822 vassert(keep);
1823 }
1824
sewardje87b4842004-07-10 12:23:30 +00001825 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001826 /* Specially handle XOR reg,reg, because that doesn't really
1827 depend on reg, and doing the obvious thing potentially
1828 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001829 dependency. Ditto SBB reg,reg. */
1830 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1831 && gregOfRM(rm) == eregOfRM(rm)) {
1832 putIReg(size, gregOfRM(rm), mkU(ty,0));
sewardje87b4842004-07-10 12:23:30 +00001833 }
sewardje87b4842004-07-10 12:23:30 +00001834 assign( dst0, getIReg(size,gregOfRM(rm)) );
1835 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00001836
sewardj180e8b32004-07-29 01:40:11 +00001837 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001838 helper_ADC( size, dst1, dst0, src,
1839 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardje87b4842004-07-10 12:23:30 +00001840 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001841 } else
1842 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001843 helper_SBB( size, dst1, dst0, src,
1844 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00001845 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1846 } else {
1847 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001848 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001849 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001850 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001851 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001852 if (keep)
1853 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1854 }
sewardje87b4842004-07-10 12:23:30 +00001855
1856 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1857 nameIReg(size,eregOfRM(rm)),
1858 nameIReg(size,gregOfRM(rm)));
1859 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001860 } else {
sewardj9334b0f2004-07-10 22:43:54 +00001861 /* E refers to memory */
1862 addr = disAMode ( &len, sorb, delta0, dis_buf);
1863 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00001864 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00001865
sewardj180e8b32004-07-29 01:40:11 +00001866 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001867 helper_ADC( size, dst1, dst0, src,
1868 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj9334b0f2004-07-10 22:43:54 +00001869 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001870 } else
1871 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001872 helper_SBB( size, dst1, dst0, src,
1873 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00001874 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1875 } else {
1876 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001877 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001878 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001879 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001880 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001881 if (keep)
1882 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1883 }
sewardj9334b0f2004-07-10 22:43:54 +00001884
sewardje87b4842004-07-10 12:23:30 +00001885 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1886 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00001887 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00001888 }
sewardje87b4842004-07-10 12:23:30 +00001889}
sewardje05c42c2004-07-08 20:25:10 +00001890
1891
1892
1893/* Handle binary integer instructions of the form
1894 op G, E meaning
1895 op reg, reg-or-mem
1896 Is passed the a ptr to the modRM byte, the actual operation, and the
1897 data size. Returns the address advanced completely over this
1898 instruction.
1899
1900 G(src) is reg.
1901 E(dst) is reg-or-mem
1902
1903 If E is reg, --> GET %E, tmp
1904 OP %G, tmp
1905 PUT tmp, %E
1906
1907 If E is mem, --> (getAddr E) -> tmpa
1908 LD (tmpa), tmpv
1909 OP %G, tmpv
1910 ST tmpv, (tmpa)
1911*/
1912static
1913UInt dis_op2_G_E ( UChar sorb,
sewardje9d8a262009-07-01 08:06:34 +00001914 Bool locked,
sewardjcaca9d02004-07-28 07:11:32 +00001915 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00001916 IROp op8,
1917 Bool keep,
1918 Int size,
sewardj52d04912005-07-03 00:52:48 +00001919 Int delta0,
sewardj2d49b432005-02-01 00:37:06 +00001920 HChar* t_x86opc )
sewardje05c42c2004-07-08 20:25:10 +00001921{
sewardjc9a43662004-11-30 18:51:59 +00001922 HChar dis_buf[50];
sewardje87b4842004-07-10 12:23:30 +00001923 Int len;
sewardje05c42c2004-07-08 20:25:10 +00001924 IRType ty = szToITy(size);
1925 IRTemp dst1 = newTemp(ty);
1926 IRTemp src = newTemp(ty);
1927 IRTemp dst0 = newTemp(ty);
1928 UChar rm = getIByte(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001929 IRTemp addr = IRTemp_INVALID;
sewardje05c42c2004-07-08 20:25:10 +00001930
sewardjcaca9d02004-07-28 07:11:32 +00001931 /* addSubCarry == True indicates the intended operation is
1932 add-with-carry or subtract-with-borrow. */
1933 if (addSubCarry) {
1934 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1935 vassert(keep);
1936 }
1937
sewardje05c42c2004-07-08 20:25:10 +00001938 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00001939 /* Specially handle XOR reg,reg, because that doesn't really
1940 depend on reg, and doing the obvious thing potentially
1941 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001942 dependency. Ditto SBB reg,reg.*/
1943 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1944 && gregOfRM(rm) == eregOfRM(rm)) {
1945 putIReg(size, eregOfRM(rm), mkU(ty,0));
sewardje05c42c2004-07-08 20:25:10 +00001946 }
sewardje05c42c2004-07-08 20:25:10 +00001947 assign(dst0, getIReg(size,eregOfRM(rm)));
1948 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001949
sewardjcaca9d02004-07-28 07:11:32 +00001950 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001951 helper_ADC( size, dst1, dst0, src,
1952 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj1813dbe2004-07-28 17:09:04 +00001953 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001954 } else
1955 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001956 helper_SBB( size, dst1, dst0, src,
1957 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardje05c42c2004-07-08 20:25:10 +00001958 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001959 } else {
1960 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00001961 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001962 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001963 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001964 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001965 if (keep)
1966 putIReg(size, eregOfRM(rm), mkexpr(dst1));
1967 }
sewardje05c42c2004-07-08 20:25:10 +00001968
1969 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1970 nameIReg(size,gregOfRM(rm)),
1971 nameIReg(size,eregOfRM(rm)));
1972 return 1+delta0;
1973 }
1974
1975 /* E refers to memory */
1976 {
sewardje87b4842004-07-10 12:23:30 +00001977 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00001978 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00001979 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001980
sewardjcaca9d02004-07-28 07:11:32 +00001981 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001982 if (locked) {
1983 /* cas-style store */
1984 helper_ADC( size, dst1, dst0, src,
1985 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
1986 } else {
1987 /* normal store */
1988 helper_ADC( size, dst1, dst0, src,
1989 /*store*/addr, IRTemp_INVALID, 0 );
1990 }
sewardjcaca9d02004-07-28 07:11:32 +00001991 } else
1992 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001993 if (locked) {
1994 /* cas-style store */
1995 helper_SBB( size, dst1, dst0, src,
1996 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
1997 } else {
1998 /* normal store */
1999 helper_SBB( size, dst1, dst0, src,
2000 /*store*/addr, IRTemp_INVALID, 0 );
2001 }
sewardjcaca9d02004-07-28 07:11:32 +00002002 } else {
2003 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00002004 if (keep) {
2005 if (locked) {
2006 if (0) vex_printf("locked case\n" );
2007 casLE( mkexpr(addr),
2008 mkexpr(dst0)/*expval*/,
2009 mkexpr(dst1)/*newval*/, guest_EIP_curr_instr );
2010 } else {
2011 if (0) vex_printf("nonlocked case\n");
2012 storeLE(mkexpr(addr), mkexpr(dst1));
2013 }
2014 }
sewardj5bd4d162004-11-10 13:02:48 +00002015 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002016 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002017 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002018 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00002019 }
sewardje87b4842004-07-10 12:23:30 +00002020
sewardje05c42c2004-07-08 20:25:10 +00002021 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2022 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00002023 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002024 }
2025}
2026
2027
2028/* Handle move instructions of the form
2029 mov E, G meaning
2030 mov reg-or-mem, reg
2031 Is passed the a ptr to the modRM byte, and the data size. Returns
2032 the address advanced completely over this instruction.
2033
2034 E(src) is reg-or-mem
2035 G(dst) is reg.
2036
2037 If E is reg, --> GET %E, tmpv
2038 PUT tmpv, %G
2039
2040 If E is mem --> (getAddr E) -> tmpa
2041 LD (tmpa), tmpb
2042 PUT tmpb, %G
2043*/
2044static
2045UInt dis_mov_E_G ( UChar sorb,
2046 Int size,
sewardj52d04912005-07-03 00:52:48 +00002047 Int delta0 )
sewardje05c42c2004-07-08 20:25:10 +00002048{
2049 Int len;
2050 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002051 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002052
2053 if (epartIsReg(rm)) {
sewardj7ca37d92004-10-25 02:58:30 +00002054 putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002055 DIP("mov%c %s,%s\n", nameISize(size),
2056 nameIReg(size,eregOfRM(rm)),
2057 nameIReg(size,gregOfRM(rm)));
sewardj7ca37d92004-10-25 02:58:30 +00002058 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002059 }
2060
2061 /* E refers to memory */
2062 {
sewardj940e8c92004-07-11 16:53:24 +00002063 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
2064 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00002065 DIP("mov%c %s,%s\n", nameISize(size),
2066 dis_buf,nameIReg(size,gregOfRM(rm)));
2067 return delta0+len;
2068 }
2069}
2070
2071
2072/* Handle move instructions of the form
2073 mov G, E meaning
2074 mov reg, reg-or-mem
2075 Is passed the a ptr to the modRM byte, and the data size. Returns
2076 the address advanced completely over this instruction.
2077
2078 G(src) is reg.
2079 E(dst) is reg-or-mem
2080
2081 If E is reg, --> GET %G, tmp
2082 PUT tmp, %E
2083
2084 If E is mem, --> (getAddr E) -> tmpa
2085 GET %G, tmpv
2086 ST tmpv, (tmpa)
2087*/
sewardjc9a65702004-07-07 16:32:57 +00002088static
2089UInt dis_mov_G_E ( UChar sorb,
2090 Int size,
sewardj52d04912005-07-03 00:52:48 +00002091 Int delta0 )
sewardjc9a65702004-07-07 16:32:57 +00002092{
sewardje05c42c2004-07-08 20:25:10 +00002093 Int len;
sewardjc9a65702004-07-07 16:32:57 +00002094 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002095 HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00002096
2097 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00002098 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00002099 DIP("mov%c %s,%s\n", nameISize(size),
2100 nameIReg(size,gregOfRM(rm)),
2101 nameIReg(size,eregOfRM(rm)));
2102 return 1+delta0;
2103 }
2104
sewardjc9a65702004-07-07 16:32:57 +00002105 /* E refers to memory */
2106 {
sewardj940e8c92004-07-11 16:53:24 +00002107 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
2108 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00002109 DIP("mov%c %s,%s\n", nameISize(size),
2110 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00002111 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00002112 }
sewardjc9a65702004-07-07 16:32:57 +00002113}
2114
2115
sewardj0611d802004-07-11 02:37:54 +00002116/* op $immediate, AL/AX/EAX. */
2117static
2118UInt dis_op_imm_A ( Int size,
sewardja718d5d2005-04-03 14:59:54 +00002119 Bool carrying,
sewardj0611d802004-07-11 02:37:54 +00002120 IROp op8,
2121 Bool keep,
sewardj52d04912005-07-03 00:52:48 +00002122 Int delta,
sewardj2d49b432005-02-01 00:37:06 +00002123 HChar* t_x86opc )
sewardj0611d802004-07-11 02:37:54 +00002124{
2125 IRType ty = szToITy(size);
2126 IRTemp dst0 = newTemp(ty);
2127 IRTemp src = newTemp(ty);
2128 IRTemp dst1 = newTemp(ty);
2129 UInt lit = getUDisp(size,delta);
2130 assign(dst0, getIReg(size,R_EAX));
2131 assign(src, mkU(ty,lit));
sewardja718d5d2005-04-03 14:59:54 +00002132
2133 if (isAddSub(op8) && !carrying) {
2134 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002135 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardja718d5d2005-04-03 14:59:54 +00002136 }
sewardjb9c5cf62004-08-24 15:10:38 +00002137 else
sewardja718d5d2005-04-03 14:59:54 +00002138 if (isLogic(op8)) {
2139 vassert(!carrying);
2140 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002141 setFlags_DEP1(op8, dst1, ty);
sewardja718d5d2005-04-03 14:59:54 +00002142 }
2143 else
2144 if (op8 == Iop_Add8 && carrying) {
sewardje9d8a262009-07-01 08:06:34 +00002145 helper_ADC( size, dst1, dst0, src,
2146 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardja718d5d2005-04-03 14:59:54 +00002147 }
sewardj2a2ba8b2004-11-08 13:14:06 +00002148 else
sewardj2fbae082005-10-03 02:07:08 +00002149 if (op8 == Iop_Sub8 && carrying) {
sewardje9d8a262009-07-01 08:06:34 +00002150 helper_SBB( size, dst1, dst0, src,
2151 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj2fbae082005-10-03 02:07:08 +00002152 }
2153 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002154 vpanic("dis_op_imm_A(x86,guest)");
sewardj0611d802004-07-11 02:37:54 +00002155
2156 if (keep)
2157 putIReg(size, R_EAX, mkexpr(dst1));
2158
2159 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
2160 lit, nameIReg(size,R_EAX));
2161 return delta+size;
2162}
sewardj9334b0f2004-07-10 22:43:54 +00002163
2164
2165/* Sign- and Zero-extending moves. */
2166static
sewardj52d04912005-07-03 00:52:48 +00002167UInt dis_movx_E_G ( UChar sorb,
2168 Int delta, Int szs, Int szd, Bool sign_extend )
sewardj9334b0f2004-07-10 22:43:54 +00002169{
sewardj9334b0f2004-07-10 22:43:54 +00002170 UChar rm = getIByte(delta);
2171 if (epartIsReg(rm)) {
sewardj33ca4ac2010-09-30 13:37:31 +00002172 if (szd == szs) {
2173 // mutant case. See #250799
2174 putIReg(szd, gregOfRM(rm),
2175 getIReg(szs,eregOfRM(rm)));
2176 } else {
2177 // normal case
2178 putIReg(szd, gregOfRM(rm),
2179 unop(mkWidenOp(szs,szd,sign_extend),
2180 getIReg(szs,eregOfRM(rm))));
2181 }
sewardj9334b0f2004-07-10 22:43:54 +00002182 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2183 nameISize(szs), nameISize(szd),
2184 nameIReg(szs,eregOfRM(rm)),
2185 nameIReg(szd,gregOfRM(rm)));
2186 return 1+delta;
2187 }
2188
2189 /* E refers to memory */
2190 {
sewardj940e8c92004-07-11 16:53:24 +00002191 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002192 HChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00002193 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj33ca4ac2010-09-30 13:37:31 +00002194 if (szd == szs) {
2195 // mutant case. See #250799
2196 putIReg(szd, gregOfRM(rm),
2197 loadLE(szToITy(szs),mkexpr(addr)));
2198 } else {
2199 // normal case
2200 putIReg(szd, gregOfRM(rm),
2201 unop(mkWidenOp(szs,szd,sign_extend),
2202 loadLE(szToITy(szs),mkexpr(addr))));
2203 }
sewardj9334b0f2004-07-10 22:43:54 +00002204 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2205 nameISize(szs), nameISize(szd),
2206 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00002207 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00002208 }
2209}
2210
sewardj9690d922004-07-14 01:39:17 +00002211
2212/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
2213 16 / 8 bit quantity in the given IRTemp. */
2214static
2215void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2216{
sewardje5427e82004-09-11 19:43:51 +00002217 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2218 IRTemp src64 = newTemp(Ity_I64);
2219 IRTemp dst64 = newTemp(Ity_I64);
sewardj9690d922004-07-14 01:39:17 +00002220 switch (sz) {
sewardje5427e82004-09-11 19:43:51 +00002221 case 4:
sewardj9690d922004-07-14 01:39:17 +00002222 assign( src64, binop(Iop_32HLto64,
sewardje5427e82004-09-11 19:43:51 +00002223 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
sewardj9690d922004-07-14 01:39:17 +00002224 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00002225 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00002226 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2227 break;
sewardje5427e82004-09-11 19:43:51 +00002228 case 2: {
2229 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2230 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2231 assign( src64, unop(widen3264,
2232 binop(Iop_16HLto32,
2233 getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2234 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2235 putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2236 putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2237 break;
sewardj9690d922004-07-14 01:39:17 +00002238 }
sewardj4e82db72004-10-16 11:32:15 +00002239 case 1: {
2240 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2241 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2242 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2243 assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2244 assign( dst64,
2245 binop(op, mkexpr(src64),
2246 unop(widen1632, unop(widen816, mkexpr(t)))) );
2247 putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2248 unop(Iop_64to32,mkexpr(dst64)))) );
2249 putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2250 unop(Iop_64HIto32,mkexpr(dst64)))) );
2251 break;
2252 }
sewardj9690d922004-07-14 01:39:17 +00002253 default: vpanic("codegen_div(x86)");
2254 }
2255}
sewardj41f43bc2004-07-08 14:23:22 +00002256
2257
2258static
sewardje9d8a262009-07-01 08:06:34 +00002259UInt dis_Grp1 ( UChar sorb, Bool locked,
sewardj52d04912005-07-03 00:52:48 +00002260 Int delta, UChar modrm,
sewardj41f43bc2004-07-08 14:23:22 +00002261 Int am_sz, Int d_sz, Int sz, UInt d32 )
2262{
sewardj41f43bc2004-07-08 14:23:22 +00002263 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002264 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002265 IRType ty = szToITy(sz);
2266 IRTemp dst1 = newTemp(ty);
2267 IRTemp src = newTemp(ty);
2268 IRTemp dst0 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002269 IRTemp addr = IRTemp_INVALID;
sewardj66de2272004-07-16 21:19:05 +00002270 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002271 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002272
2273 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002274 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002275 case 2: break; // ADC
2276 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002277 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2278 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardjd51dc812007-03-20 14:18:45 +00002279 /*NOTREACHED*/
sewardj41f43bc2004-07-08 14:23:22 +00002280 default: vpanic("dis_Grp1: unhandled case");
2281 }
sewardj41f43bc2004-07-08 14:23:22 +00002282
2283 if (epartIsReg(modrm)) {
2284 vassert(am_sz == 1);
2285
2286 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002287 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002288
sewardj180e8b32004-07-29 01:40:11 +00002289 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardje9d8a262009-07-01 08:06:34 +00002290 helper_ADC( sz, dst1, dst0, src,
2291 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00002292 } else
2293 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje9d8a262009-07-01 08:06:34 +00002294 helper_SBB( sz, dst1, dst0, src,
2295 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00002296 } else {
2297 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002298 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002299 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002300 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002301 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002302 }
sewardj41f43bc2004-07-08 14:23:22 +00002303
2304 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002305 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002306
2307 delta += (am_sz + d_sz);
2308 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2309 nameIReg(sz,eregOfRM(modrm)));
2310 } else {
sewardje87b4842004-07-10 12:23:30 +00002311 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002312
sewardj940e8c92004-07-11 16:53:24 +00002313 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002314 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002315
sewardj66de2272004-07-16 21:19:05 +00002316 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardje9d8a262009-07-01 08:06:34 +00002317 if (locked) {
2318 /* cas-style store */
2319 helper_ADC( sz, dst1, dst0, src,
2320 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2321 } else {
2322 /* normal store */
2323 helper_ADC( sz, dst1, dst0, src,
2324 /*store*/addr, IRTemp_INVALID, 0 );
2325 }
sewardj3af115f2004-07-14 02:46:52 +00002326 } else
sewardj66de2272004-07-16 21:19:05 +00002327 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje9d8a262009-07-01 08:06:34 +00002328 if (locked) {
2329 /* cas-style store */
2330 helper_SBB( sz, dst1, dst0, src,
2331 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2332 } else {
2333 /* normal store */
2334 helper_SBB( sz, dst1, dst0, src,
2335 /*store*/addr, IRTemp_INVALID, 0 );
2336 }
sewardj3af115f2004-07-14 02:46:52 +00002337 } else {
2338 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00002339 if (gregOfRM(modrm) < 7) {
2340 if (locked) {
2341 casLE( mkexpr(addr), mkexpr(dst0)/*expVal*/,
2342 mkexpr(dst1)/*newVal*/,
2343 guest_EIP_curr_instr );
2344 } else {
2345 storeLE(mkexpr(addr), mkexpr(dst1));
2346 }
2347 }
sewardj5bd4d162004-11-10 13:02:48 +00002348 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002349 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002350 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002351 setFlags_DEP1(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002352 }
sewardj41f43bc2004-07-08 14:23:22 +00002353
sewardj41f43bc2004-07-08 14:23:22 +00002354 delta += (len+d_sz);
2355 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2356 d32, dis_buf);
2357 }
2358 return delta;
2359}
2360
2361
sewardj6d2638e2004-07-15 09:38:27 +00002362/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2363 expression. */
2364
sewardje90ad6a2004-07-10 19:02:10 +00002365static
sewardj52d04912005-07-03 00:52:48 +00002366UInt dis_Grp2 ( UChar sorb,
2367 Int delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002368 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
sewardjd51dc812007-03-20 14:18:45 +00002369 HChar* shift_expr_txt, Bool* decode_OK )
sewardje90ad6a2004-07-10 19:02:10 +00002370{
2371 /* delta on entry points at the modrm byte. */
sewardjc9a43662004-11-30 18:51:59 +00002372 HChar dis_buf[50];
sewardj6d2638e2004-07-15 09:38:27 +00002373 Int len;
sewardj2eef7732005-08-23 15:41:14 +00002374 Bool isShift, isRotate, isRotateC;
sewardj6d2638e2004-07-15 09:38:27 +00002375 IRType ty = szToITy(sz);
2376 IRTemp dst0 = newTemp(ty);
2377 IRTemp dst1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002378 IRTemp addr = IRTemp_INVALID;
sewardje90ad6a2004-07-10 19:02:10 +00002379
sewardjd51dc812007-03-20 14:18:45 +00002380 *decode_OK = True;
2381
sewardje90ad6a2004-07-10 19:02:10 +00002382 vassert(sz == 1 || sz == 2 || sz == 4);
2383
sewardje90ad6a2004-07-10 19:02:10 +00002384 /* Put value to shift/rotate in dst0. */
2385 if (epartIsReg(modrm)) {
2386 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002387 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002388 } else {
sewardj940e8c92004-07-11 16:53:24 +00002389 addr = disAMode ( &len, sorb, delta, dis_buf);
2390 assign(dst0, loadLE(ty,mkexpr(addr)));
2391 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002392 }
2393
2394 isShift = False;
tomd6b43fd2011-08-19 16:06:52 +00002395 switch (gregOfRM(modrm)) { case 4: case 5: case 6: case 7: isShift = True; }
sewardje90ad6a2004-07-10 19:02:10 +00002396
sewardj750f4072004-07-26 22:39:11 +00002397 isRotate = False;
2398 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2399
sewardj2eef7732005-08-23 15:41:14 +00002400 isRotateC = False;
2401 switch (gregOfRM(modrm)) { case 2: case 3: isRotateC = True; }
sewardj9aebb0c2004-10-24 19:20:43 +00002402
sewardj2eef7732005-08-23 15:41:14 +00002403 if (!isShift && !isRotate && !isRotateC) {
sewardjd51dc812007-03-20 14:18:45 +00002404 /*NOTREACHED*/
sewardj8c7f1ab2004-07-29 20:31:09 +00002405 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2406 }
2407
sewardj2eef7732005-08-23 15:41:14 +00002408 if (isRotateC) {
2409 /* call a helper; these insns are so ridiculous they do not
2410 deserve better */
2411 Bool left = toBool(gregOfRM(modrm) == 2);
sewardj9aebb0c2004-10-24 19:20:43 +00002412 IRTemp r64 = newTemp(Ity_I64);
sewardjf9655262004-10-31 20:02:16 +00002413 IRExpr** args
2414 = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2415 widenUto32(shift_expr), /* rotate amount */
sewardj2a9ad022004-11-25 02:46:58 +00002416 widenUto32(mk_x86g_calculate_eflags_all()),
sewardjf9655262004-10-31 20:02:16 +00002417 mkU32(sz) );
2418 assign( r64, mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00002419 Ity_I64,
sewardjf9655262004-10-31 20:02:16 +00002420 0/*regparm*/,
sewardj2eef7732005-08-23 15:41:14 +00002421 left ? "x86g_calculate_RCL" : "x86g_calculate_RCR",
2422 left ? &x86g_calculate_RCL : &x86g_calculate_RCR,
sewardj8ea867b2004-10-30 19:03:02 +00002423 args
sewardjf9655262004-10-31 20:02:16 +00002424 )
2425 );
sewardj9aebb0c2004-10-24 19:20:43 +00002426 /* new eflags in hi half r64; new value in lo half r64 */
2427 assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
sewardj2a9ad022004-11-25 02:46:58 +00002428 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002429 stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
2430 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardja3b7e3a2005-04-05 01:54:19 +00002431 /* Set NDEP even though it isn't used. This makes redundant-PUT
2432 elimination of previous stores to this field work better. */
2433 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj9aebb0c2004-10-24 19:20:43 +00002434 }
2435
sewardje90ad6a2004-07-10 19:02:10 +00002436 if (isShift) {
2437
sewardjc22a6fd2004-07-29 23:41:47 +00002438 IRTemp pre32 = newTemp(Ity_I32);
2439 IRTemp res32 = newTemp(Ity_I32);
2440 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002441 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002442 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002443
2444 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002445 case 4: op32 = Iop_Shl32; break;
2446 case 5: op32 = Iop_Shr32; break;
tomd6b43fd2011-08-19 16:06:52 +00002447 case 6: op32 = Iop_Shl32; break;
sewardjc22a6fd2004-07-29 23:41:47 +00002448 case 7: op32 = Iop_Sar32; break;
sewardjd51dc812007-03-20 14:18:45 +00002449 /*NOTREACHED*/
sewardje90ad6a2004-07-10 19:02:10 +00002450 default: vpanic("dis_Grp2:shift"); break;
2451 }
2452
sewardjc22a6fd2004-07-29 23:41:47 +00002453 /* Widen the value to be shifted to 32 bits, do the shift, and
2454 narrow back down. This seems surprisingly long-winded, but
2455 unfortunately the Intel semantics requires that 8/16-bit
2456 shifts give defined results for shift values all the way up
2457 to 31, and this seems the simplest way to do it. It has the
2458 advantage that the only IR level shifts generated are of 32
2459 bit values, and the shift amount is guaranteed to be in the
2460 range 0 .. 31, thereby observing the IR semantics requiring
2461 all shift values to be in the range 0 .. 2^word_size-1. */
2462
2463 /* shift_amt = shift_expr & 31, regardless of operation size */
2464 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2465
2466 /* suitably widen the value to be shifted to 32 bits. */
2467 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2468 : widenUto32(mkexpr(dst0)) );
2469
2470 /* res32 = pre32 `shift` shift_amt */
2471 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2472
2473 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2474 assign( res32ss,
2475 binop(op32,
2476 mkexpr(pre32),
2477 binop(Iop_And8,
2478 binop(Iop_Sub8,
2479 mkexpr(shift_amt), mkU8(1)),
2480 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002481
2482 /* Build the flags thunk. */
sewardj2a2ba8b2004-11-08 13:14:06 +00002483 setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
sewardjc22a6fd2004-07-29 23:41:47 +00002484
2485 /* Narrow the result back down. */
2486 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002487
sewardj1813dbe2004-07-28 17:09:04 +00002488 } /* if (isShift) */
2489
2490 else
sewardj750f4072004-07-26 22:39:11 +00002491 if (isRotate) {
sewardj7ebbdae2004-08-26 12:30:48 +00002492 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj2d49b432005-02-01 00:37:06 +00002493 Bool left = toBool(gregOfRM(modrm) == 0);
sewardj7ebbdae2004-08-26 12:30:48 +00002494 IRTemp rot_amt = newTemp(Ity_I8);
2495 IRTemp rot_amt32 = newTemp(Ity_I8);
2496 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002497
2498 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002499 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2500 expressions never shift beyond the word size and thus remain
2501 well defined. */
sewardj7ebbdae2004-08-26 12:30:48 +00002502 assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2503
2504 if (ty == Ity_I32)
2505 assign(rot_amt, mkexpr(rot_amt32));
2506 else
2507 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
sewardj750f4072004-07-26 22:39:11 +00002508
2509 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002510
sewardj750f4072004-07-26 22:39:11 +00002511 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2512 assign(dst1,
2513 binop( mkSizedOp(ty,Iop_Or8),
2514 binop( mkSizedOp(ty,Iop_Shl8),
2515 mkexpr(dst0),
2516 mkexpr(rot_amt)
2517 ),
2518 binop( mkSizedOp(ty,Iop_Shr8),
2519 mkexpr(dst0),
2520 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2521 )
2522 )
2523 );
sewardj2a9ad022004-11-25 02:46:58 +00002524 ccOp += X86G_CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002525
sewardj1813dbe2004-07-28 17:09:04 +00002526 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002527
sewardj1813dbe2004-07-28 17:09:04 +00002528 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2529 assign(dst1,
2530 binop( mkSizedOp(ty,Iop_Or8),
2531 binop( mkSizedOp(ty,Iop_Shr8),
2532 mkexpr(dst0),
2533 mkexpr(rot_amt)
2534 ),
2535 binop( mkSizedOp(ty,Iop_Shl8),
2536 mkexpr(dst0),
2537 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002538 )
2539 )
2540 );
sewardj2a9ad022004-11-25 02:46:58 +00002541 ccOp += X86G_CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002542
sewardj750f4072004-07-26 22:39:11 +00002543 }
sewardjc22a6fd2004-07-29 23:41:47 +00002544
sewardj1813dbe2004-07-28 17:09:04 +00002545 /* dst1 now holds the rotated value. Build flag thunk. We
2546 need the resulting value for this, and the previous flags.
2547 Except don't set it if the rotate count is zero. */
2548
sewardj2a9ad022004-11-25 02:46:58 +00002549 assign(oldFlags, mk_x86g_calculate_eflags_all());
sewardj1813dbe2004-07-28 17:09:04 +00002550
sewardj2a2ba8b2004-11-08 13:14:06 +00002551 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
sewardj1813dbe2004-07-28 17:09:04 +00002552 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj7ebbdae2004-08-26 12:30:48 +00002553 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002554 IRExpr_Get(OFFB_CC_OP,Ity_I32),
2555 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002556 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj7ebbdae2004-08-26 12:30:48 +00002557 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002558 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +00002559 widenUto32(mkexpr(dst1)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002560 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj7ebbdae2004-08-26 12:30:48 +00002561 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002562 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
2563 mkU32(0))) );
2564 stmt( IRStmt_Put( OFFB_CC_NDEP,
2565 IRExpr_Mux0X( mkexpr(rot_amt32),
2566 IRExpr_Get(OFFB_CC_NDEP,Ity_I32),
sewardj1813dbe2004-07-28 17:09:04 +00002567 mkexpr(oldFlags))) );
2568 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002569
2570 /* Save result, and finish up. */
2571 if (epartIsReg(modrm)) {
2572 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002573 if (vex_traceflags & VEX_TRACE_FE) {
sewardje90ad6a2004-07-10 19:02:10 +00002574 vex_printf("%s%c ",
2575 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002576 if (shift_expr_txt)
2577 vex_printf("%s", shift_expr_txt);
2578 else
2579 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002580 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2581 }
sewardje90ad6a2004-07-10 19:02:10 +00002582 } else {
sewardj940e8c92004-07-11 16:53:24 +00002583 storeLE(mkexpr(addr), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002584 if (vex_traceflags & VEX_TRACE_FE) {
sewardj940e8c92004-07-11 16:53:24 +00002585 vex_printf("%s%c ",
2586 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002587 if (shift_expr_txt)
2588 vex_printf("%s", shift_expr_txt);
2589 else
2590 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002591 vex_printf(", %s\n", dis_buf);
2592 }
sewardje90ad6a2004-07-10 19:02:10 +00002593 }
sewardje90ad6a2004-07-10 19:02:10 +00002594 return delta;
2595}
2596
2597
sewardj490ad382005-03-13 17:25:53 +00002598/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2599static
sewardj52d04912005-07-03 00:52:48 +00002600UInt dis_Grp8_Imm ( UChar sorb,
sewardje9d8a262009-07-01 08:06:34 +00002601 Bool locked,
sewardj52d04912005-07-03 00:52:48 +00002602 Int delta, UChar modrm,
sewardj490ad382005-03-13 17:25:53 +00002603 Int am_sz, Int sz, UInt src_val,
2604 Bool* decode_OK )
2605{
2606 /* src_val denotes a d8.
2607 And delta on entry points at the modrm byte. */
sewardje90ad6a2004-07-10 19:02:10 +00002608
sewardj490ad382005-03-13 17:25:53 +00002609 IRType ty = szToITy(sz);
2610 IRTemp t2 = newTemp(Ity_I32);
2611 IRTemp t2m = newTemp(Ity_I32);
2612 IRTemp t_addr = IRTemp_INVALID;
2613 HChar dis_buf[50];
2614 UInt mask;
sewardjd1061ab2004-07-08 01:45:30 +00002615
sewardj490ad382005-03-13 17:25:53 +00002616 /* we're optimists :-) */
2617 *decode_OK = True;
sewardjd1061ab2004-07-08 01:45:30 +00002618
sewardj490ad382005-03-13 17:25:53 +00002619 /* Limit src_val -- the bit offset -- to something within a word.
2620 The Intel docs say that literal offsets larger than a word are
2621 masked in this way. */
2622 switch (sz) {
2623 case 2: src_val &= 15; break;
2624 case 4: src_val &= 31; break;
2625 default: *decode_OK = False; return delta;
2626 }
sewardjcf780b42004-07-13 18:42:17 +00002627
sewardj490ad382005-03-13 17:25:53 +00002628 /* Invent a mask suitable for the operation. */
2629 switch (gregOfRM(modrm)) {
2630 case 4: /* BT */ mask = 0; break;
2631 case 5: /* BTS */ mask = 1 << src_val; break;
2632 case 6: /* BTR */ mask = ~(1 << src_val); break;
2633 case 7: /* BTC */ mask = 1 << src_val; break;
2634 /* If this needs to be extended, probably simplest to make a
2635 new function to handle the other cases (0 .. 3). The
2636 Intel docs do however not indicate any use for 0 .. 3, so
2637 we don't expect this to happen. */
2638 default: *decode_OK = False; return delta;
2639 }
2640
2641 /* Fetch the value to be tested and modified into t2, which is
2642 32-bits wide regardless of sz. */
2643 if (epartIsReg(modrm)) {
2644 vassert(am_sz == 1);
sewardj5a8334e2005-03-13 19:52:45 +00002645 assign( t2, widenUto32(getIReg(sz, eregOfRM(modrm))) );
sewardj490ad382005-03-13 17:25:53 +00002646 delta += (am_sz + 1);
2647 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2648 src_val, nameIReg(sz,eregOfRM(modrm)));
2649 } else {
2650 Int len;
2651 t_addr = disAMode ( &len, sorb, delta, dis_buf);
2652 delta += (len+1);
2653 assign( t2, widenUto32(loadLE(ty, mkexpr(t_addr))) );
2654 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2655 src_val, dis_buf);
2656 }
2657
sewardj490ad382005-03-13 17:25:53 +00002658 /* Compute the new value into t2m, if non-BT. */
2659 switch (gregOfRM(modrm)) {
2660 case 4: /* BT */
2661 break;
2662 case 5: /* BTS */
2663 assign( t2m, binop(Iop_Or32, mkU32(mask), mkexpr(t2)) );
2664 break;
2665 case 6: /* BTR */
2666 assign( t2m, binop(Iop_And32, mkU32(mask), mkexpr(t2)) );
2667 break;
2668 case 7: /* BTC */
2669 assign( t2m, binop(Iop_Xor32, mkU32(mask), mkexpr(t2)) );
2670 break;
sewardjba89f4c2005-04-07 17:31:27 +00002671 default:
2672 /*NOTREACHED*/ /*the previous switch guards this*/
sewardj490ad382005-03-13 17:25:53 +00002673 vassert(0);
2674 }
2675
sewardje9d8a262009-07-01 08:06:34 +00002676 /* Write the result back, if non-BT. If the CAS fails then we
2677 side-exit from the trace at this point, and so the flag state is
2678 not affected. This is of course as required. */
sewardj490ad382005-03-13 17:25:53 +00002679 if (gregOfRM(modrm) != 4 /* BT */) {
2680 if (epartIsReg(modrm)) {
sewardje9d8a262009-07-01 08:06:34 +00002681 putIReg(sz, eregOfRM(modrm), narrowTo(ty, mkexpr(t2m)));
sewardj490ad382005-03-13 17:25:53 +00002682 } else {
sewardje9d8a262009-07-01 08:06:34 +00002683 if (locked) {
2684 casLE( mkexpr(t_addr),
2685 narrowTo(ty, mkexpr(t2))/*expd*/,
2686 narrowTo(ty, mkexpr(t2m))/*new*/,
2687 guest_EIP_curr_instr );
2688 } else {
2689 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
2690 }
sewardj490ad382005-03-13 17:25:53 +00002691 }
2692 }
2693
sewardje9d8a262009-07-01 08:06:34 +00002694 /* Copy relevant bit from t2 into the carry flag. */
2695 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
2696 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
2697 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2698 stmt( IRStmt_Put(
2699 OFFB_CC_DEP1,
2700 binop(Iop_And32,
2701 binop(Iop_Shr32, mkexpr(t2), mkU8(src_val)),
2702 mkU32(1))
2703 ));
2704 /* Set NDEP even though it isn't used. This makes redundant-PUT
2705 elimination of previous stores to this field work better. */
2706 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
2707
sewardj490ad382005-03-13 17:25:53 +00002708 return delta;
2709}
sewardjcf780b42004-07-13 18:42:17 +00002710
2711
sewardj1813dbe2004-07-28 17:09:04 +00002712/* Signed/unsigned widening multiply. Generate IR to multiply the
2713 value in EAX/AX/AL by the given IRTemp, and park the result in
2714 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002715*/
sewardj1813dbe2004-07-28 17:09:04 +00002716static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj2d49b432005-02-01 00:37:06 +00002717 IRTemp tmp, HChar* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002718{
sewardjcf780b42004-07-13 18:42:17 +00002719 IRType ty = szToITy(sz);
2720 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002721
sewardj1813dbe2004-07-28 17:09:04 +00002722 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002723
2724 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002725 case Ity_I32: {
2726 IRTemp res64 = newTemp(Ity_I64);
sewardj948d48b2004-11-05 19:49:09 +00002727 IRTemp resHi = newTemp(Ity_I32);
2728 IRTemp resLo = newTemp(Ity_I32);
sewardjb81f8b32004-07-30 10:17:50 +00002729 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
sewardj2a9ad022004-11-25 02:46:58 +00002730 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002731 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002732 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002733 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2734 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj948d48b2004-11-05 19:49:09 +00002735 putIReg(4, R_EDX, mkexpr(resHi));
2736 putIReg(4, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002737 break;
2738 }
2739 case Ity_I16: {
2740 IRTemp res32 = newTemp(Ity_I32);
sewardj948d48b2004-11-05 19:49:09 +00002741 IRTemp resHi = newTemp(Ity_I16);
2742 IRTemp resLo = newTemp(Ity_I16);
sewardjb81f8b32004-07-30 10:17:50 +00002743 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
sewardj2a9ad022004-11-25 02:46:58 +00002744 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002745 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002746 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002747 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2748 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj948d48b2004-11-05 19:49:09 +00002749 putIReg(2, R_EDX, mkexpr(resHi));
2750 putIReg(2, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002751 break;
2752 }
2753 case Ity_I8: {
2754 IRTemp res16 = newTemp(Ity_I16);
sewardj948d48b2004-11-05 19:49:09 +00002755 IRTemp resHi = newTemp(Ity_I8);
2756 IRTemp resLo = newTemp(Ity_I8);
sewardjb81f8b32004-07-30 10:17:50 +00002757 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
sewardj2a9ad022004-11-25 02:46:58 +00002758 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002759 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002760 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002761 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2762 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardjb81f8b32004-07-30 10:17:50 +00002763 putIReg(2, R_EAX, mkexpr(res16));
2764 break;
2765 }
2766 default:
2767 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002768 }
sewardj1813dbe2004-07-28 17:09:04 +00002769 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002770}
2771
sewardj940e8c92004-07-11 16:53:24 +00002772
2773/* Group 3 extended opcodes. */
2774static
sewardje9d8a262009-07-01 08:06:34 +00002775UInt dis_Grp3 ( UChar sorb, Bool locked, Int sz, Int delta, Bool* decode_OK )
sewardj940e8c92004-07-11 16:53:24 +00002776{
sewardjc9a43662004-11-30 18:51:59 +00002777 UInt d32;
2778 UChar modrm;
2779 HChar dis_buf[50];
2780 Int len;
sewardjc2ac51e2004-07-12 01:03:26 +00002781 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002782 IRType ty = szToITy(sz);
2783 IRTemp t1 = newTemp(ty);
sewardj940e8c92004-07-11 16:53:24 +00002784 IRTemp dst1, src, dst0;
sewardjd51dc812007-03-20 14:18:45 +00002785
2786 *decode_OK = True; /* may change this later */
2787
sewardj940e8c92004-07-11 16:53:24 +00002788 modrm = getIByte(delta);
sewardje9d8a262009-07-01 08:06:34 +00002789
2790 if (locked && (gregOfRM(modrm) != 2 && gregOfRM(modrm) != 3)) {
2791 /* LOCK prefix only allowed with not and neg subopcodes */
2792 *decode_OK = False;
2793 return delta;
2794 }
2795
sewardj940e8c92004-07-11 16:53:24 +00002796 if (epartIsReg(modrm)) {
2797 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002798 case 0: { /* TEST */
2799 delta++; d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002800 dst1 = newTemp(ty);
2801 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2802 getIReg(sz,eregOfRM(modrm)),
sewardjc2ac51e2004-07-12 01:03:26 +00002803 mkU(ty,d32)));
sewardj5bd4d162004-11-10 13:02:48 +00002804 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002805 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2806 nameIReg(sz, eregOfRM(modrm)));
2807 break;
2808 }
sewardjd51dc812007-03-20 14:18:45 +00002809 case 1: /* UNDEFINED */
2810 /* The Intel docs imply this insn is undefined and binutils
2811 agrees. Unfortunately Core 2 will run it (with who
2812 knows what result?) sandpile.org reckons it's an alias
2813 for case 0. We play safe. */
2814 *decode_OK = False;
2815 break;
sewardj940e8c92004-07-11 16:53:24 +00002816 case 2: /* NOT */
2817 delta++;
2818 putIReg(sz, eregOfRM(modrm),
2819 unop(mkSizedOp(ty,Iop_Not8),
2820 getIReg(sz, eregOfRM(modrm))));
2821 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2822 break;
2823 case 3: /* NEG */
2824 delta++;
2825 dst0 = newTemp(ty);
2826 src = newTemp(ty);
2827 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002828 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002829 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardjeb17e492007-08-25 23:07:44 +00002830 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002831 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002832 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj940e8c92004-07-11 16:53:24 +00002833 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2834 break;
sewardjcf780b42004-07-13 18:42:17 +00002835 case 4: /* MUL (unsigned widening) */
2836 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002837 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002838 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002839 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002840 break;
sewardjcaca9d02004-07-28 07:11:32 +00002841 case 5: /* IMUL (signed widening) */
2842 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002843 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002844 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002845 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002846 break;
sewardj68511542004-07-28 00:15:44 +00002847 case 6: /* DIV */
2848 delta++;
2849 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2850 codegen_div ( sz, t1, False );
2851 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2852 break;
sewardjcaca9d02004-07-28 07:11:32 +00002853 case 7: /* IDIV */
2854 delta++;
2855 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2856 codegen_div ( sz, t1, True );
2857 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2858 break;
sewardj940e8c92004-07-11 16:53:24 +00002859 default:
sewardjd51dc812007-03-20 14:18:45 +00002860 /* This can't happen - gregOfRM should return 0 .. 7 only */
sewardj940e8c92004-07-11 16:53:24 +00002861 vpanic("Grp3(x86)");
2862 }
2863 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002864 addr = disAMode ( &len, sorb, delta, dis_buf );
2865 t1 = newTemp(ty);
2866 delta += len;
2867 assign(t1, loadLE(ty,mkexpr(addr)));
2868 switch (gregOfRM(modrm)) {
2869 case 0: { /* TEST */
2870 d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002871 dst1 = newTemp(ty);
2872 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2873 mkexpr(t1), mkU(ty,d32)));
2874 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002875 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2876 break;
2877 }
sewardjd51dc812007-03-20 14:18:45 +00002878 case 1: /* UNDEFINED */
2879 /* See comment above on R case */
2880 *decode_OK = False;
2881 break;
sewardj78fe7912004-08-20 23:38:07 +00002882 case 2: /* NOT */
sewardje9d8a262009-07-01 08:06:34 +00002883 dst1 = newTemp(ty);
2884 assign(dst1, unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2885 if (locked) {
2886 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2887 guest_EIP_curr_instr );
2888 } else {
2889 storeLE( mkexpr(addr), mkexpr(dst1) );
2890 }
sewardj78fe7912004-08-20 23:38:07 +00002891 DIP("not%c %s\n", nameISize(sz), dis_buf);
2892 break;
sewardj0c12ea82004-07-12 08:18:16 +00002893 case 3: /* NEG */
2894 dst0 = newTemp(ty);
2895 src = newTemp(ty);
2896 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002897 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002898 assign(src, mkexpr(t1));
sewardje9d8a262009-07-01 08:06:34 +00002899 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8),
2900 mkexpr(dst0), mkexpr(src)));
2901 if (locked) {
2902 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2903 guest_EIP_curr_instr );
2904 } else {
2905 storeLE( mkexpr(addr), mkexpr(dst1) );
2906 }
sewardj2a2ba8b2004-11-08 13:14:06 +00002907 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj0c12ea82004-07-12 08:18:16 +00002908 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2909 break;
sewardj1813dbe2004-07-28 17:09:04 +00002910 case 4: /* MUL */
2911 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2912 break;
2913 case 5: /* IMUL */
2914 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2915 break;
sewardj9690d922004-07-14 01:39:17 +00002916 case 6: /* DIV */
2917 codegen_div ( sz, t1, False );
2918 DIP("div%c %s\n", nameISize(sz), dis_buf);
2919 break;
sewardj1813dbe2004-07-28 17:09:04 +00002920 case 7: /* IDIV */
2921 codegen_div ( sz, t1, True );
2922 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2923 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002924 default:
sewardjd51dc812007-03-20 14:18:45 +00002925 /* This can't happen - gregOfRM should return 0 .. 7 only */
sewardjc2ac51e2004-07-12 01:03:26 +00002926 vpanic("Grp3(x86)");
2927 }
sewardj940e8c92004-07-11 16:53:24 +00002928 }
2929 return delta;
2930}
2931
2932
sewardjc2ac51e2004-07-12 01:03:26 +00002933/* Group 4 extended opcodes. */
2934static
sewardje9d8a262009-07-01 08:06:34 +00002935UInt dis_Grp4 ( UChar sorb, Bool locked, Int delta, Bool* decode_OK )
sewardjc2ac51e2004-07-12 01:03:26 +00002936{
sewardjc9a43662004-11-30 18:51:59 +00002937 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00002938 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00002939 HChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002940 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00002941 IRTemp t1 = newTemp(ty);
2942 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002943
sewardjd51dc812007-03-20 14:18:45 +00002944 *decode_OK = True;
2945
sewardjc2ac51e2004-07-12 01:03:26 +00002946 modrm = getIByte(delta);
sewardje9d8a262009-07-01 08:06:34 +00002947
2948 if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
2949 /* LOCK prefix only allowed with inc and dec subopcodes */
2950 *decode_OK = False;
2951 return delta;
2952 }
2953
sewardjc2ac51e2004-07-12 01:03:26 +00002954 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002955 assign(t1, getIReg(1, eregOfRM(modrm)));
2956 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00002957 case 0: /* INC */
2958 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2959 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2960 setFlags_INC_DEC( True, t2, ty );
2961 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002962 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00002963 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2964 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2965 setFlags_INC_DEC( False, t2, ty );
2966 break;
2967 default:
sewardjd51dc812007-03-20 14:18:45 +00002968 *decode_OK = False;
2969 return delta;
sewardjc2ac51e2004-07-12 01:03:26 +00002970 }
2971 delta++;
2972 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
2973 nameIReg(1, eregOfRM(modrm)));
2974 } else {
sewardj7ed22952004-07-29 00:09:58 +00002975 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
2976 assign( t1, loadLE(ty, mkexpr(addr)) );
2977 switch (gregOfRM(modrm)) {
sewardj588ea762004-09-10 18:56:32 +00002978 case 0: /* INC */
2979 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardje9d8a262009-07-01 08:06:34 +00002980 if (locked) {
2981 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
2982 guest_EIP_curr_instr );
2983 } else {
2984 storeLE( mkexpr(addr), mkexpr(t2) );
2985 }
sewardj588ea762004-09-10 18:56:32 +00002986 setFlags_INC_DEC( True, t2, ty );
2987 break;
sewardj7ed22952004-07-29 00:09:58 +00002988 case 1: /* DEC */
2989 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardje9d8a262009-07-01 08:06:34 +00002990 if (locked) {
2991 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
2992 guest_EIP_curr_instr );
2993 } else {
2994 storeLE( mkexpr(addr), mkexpr(t2) );
2995 }
sewardj7ed22952004-07-29 00:09:58 +00002996 setFlags_INC_DEC( False, t2, ty );
2997 break;
2998 default:
sewardjd51dc812007-03-20 14:18:45 +00002999 *decode_OK = False;
3000 return delta;
sewardj7ed22952004-07-29 00:09:58 +00003001 }
3002 delta += alen;
3003 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00003004 }
3005 return delta;
3006}
sewardj0611d802004-07-11 02:37:54 +00003007
3008
3009/* Group 5 extended opcodes. */
3010static
sewardje9d8a262009-07-01 08:06:34 +00003011UInt dis_Grp5 ( UChar sorb, Bool locked, Int sz, Int delta,
sewardjd51dc812007-03-20 14:18:45 +00003012 DisResult* dres, Bool* decode_OK )
sewardj0611d802004-07-11 02:37:54 +00003013{
3014 Int len;
3015 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00003016 HChar dis_buf[50];
sewardj92d168d2004-11-15 14:22:12 +00003017 IRTemp addr = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00003018 IRType ty = szToITy(sz);
3019 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00003020 IRTemp t2 = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00003021
sewardjd51dc812007-03-20 14:18:45 +00003022 *decode_OK = True;
3023
sewardj0611d802004-07-11 02:37:54 +00003024 modrm = getIByte(delta);
sewardje9d8a262009-07-01 08:06:34 +00003025
3026 if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
3027 /* LOCK prefix only allowed with inc and dec subopcodes */
3028 *decode_OK = False;
3029 return delta;
3030 }
3031
sewardj0611d802004-07-11 02:37:54 +00003032 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00003033 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00003034 switch (gregOfRM(modrm)) {
sewardj59ff5d42005-10-05 10:39:58 +00003035 case 0: /* INC */
3036 vassert(sz == 2 || sz == 4);
3037 t2 = newTemp(ty);
3038 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3039 mkexpr(t1), mkU(ty,1)));
3040 setFlags_INC_DEC( True, t2, ty );
3041 putIReg(sz,eregOfRM(modrm),mkexpr(t2));
3042 break;
3043 case 1: /* DEC */
3044 vassert(sz == 2 || sz == 4);
3045 t2 = newTemp(ty);
3046 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3047 mkexpr(t1), mkU(ty,1)));
3048 setFlags_INC_DEC( False, t2, ty );
3049 putIReg(sz,eregOfRM(modrm),mkexpr(t2));
3050 break;
sewardjc2ac51e2004-07-12 01:03:26 +00003051 case 2: /* call Ev */
3052 vassert(sz == 4);
3053 t2 = newTemp(Ity_I32);
3054 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3055 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003056 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+1));
sewardj5bd4d162004-11-10 13:02:48 +00003057 jmp_treg(Ijk_Call,t1);
sewardj9e6491a2005-07-02 19:24:10 +00003058 dres->whatNext = Dis_StopHere;
sewardjc2ac51e2004-07-12 01:03:26 +00003059 break;
sewardj0611d802004-07-11 02:37:54 +00003060 case 4: /* jmp Ev */
3061 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00003062 jmp_treg(Ijk_Boring,t1);
sewardj9e6491a2005-07-02 19:24:10 +00003063 dres->whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +00003064 break;
sewardj28905822006-11-18 22:56:46 +00003065 case 6: /* PUSH Ev */
3066 vassert(sz == 4 || sz == 2);
3067 t2 = newTemp(Ity_I32);
3068 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3069 putIReg(4, R_ESP, mkexpr(t2) );
3070 storeLE( mkexpr(t2), mkexpr(t1) );
3071 break;
sewardj0611d802004-07-11 02:37:54 +00003072 default:
sewardjd51dc812007-03-20 14:18:45 +00003073 *decode_OK = False;
3074 return delta;
sewardj0611d802004-07-11 02:37:54 +00003075 }
3076 delta++;
3077 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3078 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
3079 } else {
3080 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00003081 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00003082 switch (gregOfRM(modrm)) {
3083 case 0: /* INC */
3084 t2 = newTemp(ty);
3085 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
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 }
sewardj0611d802004-07-11 02:37:54 +00003093 setFlags_INC_DEC( True, t2, ty );
sewardj0611d802004-07-11 02:37:54 +00003094 break;
sewardjc2ac51e2004-07-12 01:03:26 +00003095 case 1: /* DEC */
3096 t2 = newTemp(ty);
3097 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3098 mkexpr(t1), mkU(ty,1)));
sewardje9d8a262009-07-01 08:06:34 +00003099 if (locked) {
3100 casLE( mkexpr(addr),
3101 mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3102 } else {
3103 storeLE(mkexpr(addr),mkexpr(t2));
3104 }
sewardjc2ac51e2004-07-12 01:03:26 +00003105 setFlags_INC_DEC( False, t2, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00003106 break;
sewardj77b86be2004-07-11 13:28:24 +00003107 case 2: /* call Ev */
3108 vassert(sz == 4);
3109 t2 = newTemp(Ity_I32);
3110 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3111 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003112 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+len));
sewardj5bd4d162004-11-10 13:02:48 +00003113 jmp_treg(Ijk_Call,t1);
sewardj9e6491a2005-07-02 19:24:10 +00003114 dres->whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00003115 break;
3116 case 4: /* JMP Ev */
3117 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00003118 jmp_treg(Ijk_Boring,t1);
sewardj9e6491a2005-07-02 19:24:10 +00003119 dres->whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00003120 break;
sewardj0c12ea82004-07-12 08:18:16 +00003121 case 6: /* PUSH Ev */
3122 vassert(sz == 4 || sz == 2);
3123 t2 = newTemp(Ity_I32);
3124 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3125 putIReg(4, R_ESP, mkexpr(t2) );
sewardj5bd4d162004-11-10 13:02:48 +00003126 storeLE( mkexpr(t2), mkexpr(t1) );
sewardj0c12ea82004-07-12 08:18:16 +00003127 break;
sewardj0611d802004-07-11 02:37:54 +00003128 default:
sewardjd51dc812007-03-20 14:18:45 +00003129 *decode_OK = False;
3130 return delta;
sewardj0611d802004-07-11 02:37:54 +00003131 }
3132 delta += len;
3133 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3134 nameISize(sz), dis_buf);
3135 }
3136 return delta;
3137}
3138
sewardj464efa42004-11-19 22:17:29 +00003139
sewardj64e1d652004-07-12 14:00:46 +00003140/*------------------------------------------------------------*/
3141/*--- Disassembling string ops (including REP prefixes) ---*/
3142/*------------------------------------------------------------*/
3143
3144/* Code shared by all the string ops */
3145static
3146void dis_string_op_increment(Int sz, Int t_inc)
3147{
3148 if (sz == 4 || sz == 2) {
3149 assign( t_inc,
3150 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00003151 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00003152 } else {
3153 assign( t_inc,
3154 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
3155 }
3156}
3157
sewardj64e1d652004-07-12 14:00:46 +00003158static
3159void dis_string_op( void (*dis_OP)( Int, IRTemp ),
sewardj2d49b432005-02-01 00:37:06 +00003160 Int sz, HChar* name, UChar sorb )
sewardj64e1d652004-07-12 14:00:46 +00003161{
3162 IRTemp t_inc = newTemp(Ity_I32);
sewardj9c3b25a2007-04-05 15:06:56 +00003163 vassert(sorb == 0); /* hmm. so what was the point of passing it in? */
sewardj64e1d652004-07-12 14:00:46 +00003164 dis_string_op_increment(sz, t_inc);
3165 dis_OP( sz, t_inc );
3166 DIP("%s%c\n", name, nameISize(sz));
3167}
sewardj64e1d652004-07-12 14:00:46 +00003168
3169static
3170void dis_MOVS ( Int sz, IRTemp t_inc )
3171{
3172 IRType ty = szToITy(sz);
sewardj64e1d652004-07-12 14:00:46 +00003173 IRTemp td = newTemp(Ity_I32); /* EDI */
3174 IRTemp ts = newTemp(Ity_I32); /* ESI */
3175
sewardj64e1d652004-07-12 14:00:46 +00003176 assign( td, getIReg(4, R_EDI) );
3177 assign( ts, getIReg(4, R_ESI) );
3178
sewardj64e1d652004-07-12 14:00:46 +00003179 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3180
sewardj64e1d652004-07-12 14:00:46 +00003181 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3182 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3183}
3184
sewardj10ca4eb2005-05-30 11:19:54 +00003185static
3186void dis_LODS ( Int sz, IRTemp t_inc )
3187{
3188 IRType ty = szToITy(sz);
3189 IRTemp ts = newTemp(Ity_I32); /* ESI */
3190
3191 assign( ts, getIReg(4, R_ESI) );
3192
3193 putIReg( sz, R_EAX, loadLE(ty, mkexpr(ts)) );
3194
3195 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3196}
sewardj64e1d652004-07-12 14:00:46 +00003197
3198static
3199void dis_STOS ( Int sz, IRTemp t_inc )
3200{
3201 IRType ty = szToITy(sz);
3202 IRTemp ta = newTemp(ty); /* EAX */
3203 IRTemp td = newTemp(Ity_I32); /* EDI */
3204
sewardj64e1d652004-07-12 14:00:46 +00003205 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003206 assign( td, getIReg(4, R_EDI) );
3207
sewardj6d2638e2004-07-15 09:38:27 +00003208 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00003209
sewardj64e1d652004-07-12 14:00:46 +00003210 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3211}
3212
3213static
3214void dis_CMPS ( Int sz, IRTemp t_inc )
3215{
3216 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00003217 IRTemp tdv = newTemp(ty); /* (EDI) */
3218 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj64e1d652004-07-12 14:00:46 +00003219 IRTemp td = newTemp(Ity_I32); /* EDI */
3220 IRTemp ts = newTemp(Ity_I32); /* ESI */
3221
sewardj64e1d652004-07-12 14:00:46 +00003222 assign( td, getIReg(4, R_EDI) );
sewardj64e1d652004-07-12 14:00:46 +00003223 assign( ts, getIReg(4, R_ESI) );
3224
sewardj64e1d652004-07-12 14:00:46 +00003225 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardjb9c5cf62004-08-24 15:10:38 +00003226 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00003227
sewardj2a2ba8b2004-11-08 13:14:06 +00003228 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003229
sewardj64e1d652004-07-12 14:00:46 +00003230 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
sewardj64e1d652004-07-12 14:00:46 +00003231 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3232}
3233
sewardj64e1d652004-07-12 14:00:46 +00003234static
3235void dis_SCAS ( Int sz, IRTemp t_inc )
3236{
3237 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00003238 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00003239 IRTemp td = newTemp(Ity_I32); /* EDI */
3240 IRTemp tdv = newTemp(ty); /* (EDI) */
3241
sewardjb9c5cf62004-08-24 15:10:38 +00003242 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003243 assign( td, getIReg(4, R_EDI) );
3244
sewardj64e1d652004-07-12 14:00:46 +00003245 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00003246 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003247
sewardj64e1d652004-07-12 14:00:46 +00003248 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3249}
sewardj82292882004-07-27 00:15:59 +00003250
sewardj64e1d652004-07-12 14:00:46 +00003251
3252/* Wrap the appropriate string op inside a REP/REPE/REPNE.
3253 We assume the insn is the last one in the basic block, and so emit a jump
3254 to the next insn, rather than just falling through. */
3255static
sewardj2a9ad022004-11-25 02:46:58 +00003256void dis_REP_op ( X86Condcode cond,
sewardj64e1d652004-07-12 14:00:46 +00003257 void (*dis_OP)(Int, IRTemp),
sewardj2d49b432005-02-01 00:37:06 +00003258 Int sz, Addr32 eip, Addr32 eip_next, HChar* name )
sewardj64e1d652004-07-12 14:00:46 +00003259{
3260 IRTemp t_inc = newTemp(Ity_I32);
3261 IRTemp tc = newTemp(Ity_I32); /* ECX */
3262
sewardj64e1d652004-07-12 14:00:46 +00003263 assign( tc, getIReg(4,R_ECX) );
3264
sewardj64e1d652004-07-12 14:00:46 +00003265 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +00003266 Ijk_Boring,
sewardj64e1d652004-07-12 14:00:46 +00003267 IRConst_U32(eip_next) ) );
3268
sewardj64e1d652004-07-12 14:00:46 +00003269 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
3270
3271 dis_string_op_increment(sz, t_inc);
3272 dis_OP (sz, t_inc);
3273
sewardj2a9ad022004-11-25 02:46:58 +00003274 if (cond == X86CondAlways) {
sewardj78c19df2004-07-12 22:49:27 +00003275 jmp_lit(Ijk_Boring,eip);
sewardj64e1d652004-07-12 14:00:46 +00003276 } else {
sewardj2a9ad022004-11-25 02:46:58 +00003277 stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
sewardj893aada2004-11-29 19:57:54 +00003278 Ijk_Boring,
sewardj5bd4d162004-11-10 13:02:48 +00003279 IRConst_U32(eip) ) );
sewardj78c19df2004-07-12 22:49:27 +00003280 jmp_lit(Ijk_Boring,eip_next);
sewardj64e1d652004-07-12 14:00:46 +00003281 }
3282 DIP("%s%c\n", name, nameISize(sz));
3283}
3284
sewardj464efa42004-11-19 22:17:29 +00003285
sewardj64e1d652004-07-12 14:00:46 +00003286/*------------------------------------------------------------*/
3287/*--- Arithmetic, etc. ---*/
3288/*------------------------------------------------------------*/
3289
sewardj2a2ba8b2004-11-08 13:14:06 +00003290/* IMUL E, G. Supplied eip points to the modR/M byte. */
sewardjcf780b42004-07-13 18:42:17 +00003291static
3292UInt dis_mul_E_G ( UChar sorb,
3293 Int size,
sewardj52d04912005-07-03 00:52:48 +00003294 Int delta0 )
sewardjcf780b42004-07-13 18:42:17 +00003295{
sewardj71a65362004-07-28 01:48:34 +00003296 Int alen;
sewardjc9a43662004-11-30 18:51:59 +00003297 HChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00003298 UChar rm = getIByte(delta0);
3299 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00003300 IRTemp te = newTemp(ty);
3301 IRTemp tg = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003302 IRTemp resLo = newTemp(ty);
sewardj71a65362004-07-28 01:48:34 +00003303
sewardj948d48b2004-11-05 19:49:09 +00003304 assign( tg, getIReg(size, gregOfRM(rm)) );
sewardjcf780b42004-07-13 18:42:17 +00003305 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00003306 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj948d48b2004-11-05 19:49:09 +00003307 } else {
3308 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3309 assign( te, loadLE(ty,mkexpr(addr)) );
3310 }
sewardjcf780b42004-07-13 18:42:17 +00003311
sewardj2a9ad022004-11-25 02:46:58 +00003312 setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003313
sewardj2a2ba8b2004-11-08 13:14:06 +00003314 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
sewardj948d48b2004-11-05 19:49:09 +00003315
3316 putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3317
3318 if (epartIsReg(rm)) {
sewardj2a2ba8b2004-11-08 13:14:06 +00003319 DIP("imul%c %s, %s\n", nameISize(size),
3320 nameIReg(size,eregOfRM(rm)),
3321 nameIReg(size,gregOfRM(rm)));
sewardjcf780b42004-07-13 18:42:17 +00003322 return 1+delta0;
3323 } else {
sewardj2a2ba8b2004-11-08 13:14:06 +00003324 DIP("imul%c %s, %s\n", nameISize(size),
3325 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00003326 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00003327 }
3328}
3329
3330
sewardj1813dbe2004-07-28 17:09:04 +00003331/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
3332static
3333UInt dis_imul_I_E_G ( UChar sorb,
3334 Int size,
sewardj52d04912005-07-03 00:52:48 +00003335 Int delta,
sewardj1813dbe2004-07-28 17:09:04 +00003336 Int litsize )
3337{
sewardj883b00b2004-09-11 09:30:24 +00003338 Int d32, alen;
sewardjc9a43662004-11-30 18:51:59 +00003339 HChar dis_buf[50];
sewardjb81f8b32004-07-30 10:17:50 +00003340 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00003341 IRType ty = szToITy(size);
3342 IRTemp te = newTemp(ty);
3343 IRTemp tl = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003344 IRTemp resLo = newTemp(ty);
sewardj1813dbe2004-07-28 17:09:04 +00003345
sewardjb81f8b32004-07-30 10:17:50 +00003346 vassert(size == 1 || size == 2 || size == 4);
3347
sewardj1813dbe2004-07-28 17:09:04 +00003348 if (epartIsReg(rm)) {
3349 assign(te, getIReg(size, eregOfRM(rm)));
3350 delta++;
3351 } else {
sewardj883b00b2004-09-11 09:30:24 +00003352 IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3353 assign(te, loadLE(ty, mkexpr(addr)));
3354 delta += alen;
sewardj1813dbe2004-07-28 17:09:04 +00003355 }
3356 d32 = getSDisp(litsize,delta);
3357 delta += litsize;
3358
sewardjb81f8b32004-07-30 10:17:50 +00003359 if (size == 1) d32 &= 0xFF;
3360 if (size == 2) d32 &= 0xFFFF;
3361
sewardj1813dbe2004-07-28 17:09:04 +00003362 assign(tl, mkU(ty,d32));
sewardj948d48b2004-11-05 19:49:09 +00003363
sewardj2a2ba8b2004-11-08 13:14:06 +00003364 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
sewardj948d48b2004-11-05 19:49:09 +00003365
sewardj2a9ad022004-11-25 02:46:58 +00003366 setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003367
3368 putIReg(size, gregOfRM(rm), mkexpr(resLo));
sewardj1813dbe2004-07-28 17:09:04 +00003369
3370 DIP("imul %d, %s, %s\n", d32,
3371 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3372 nameIReg(size,gregOfRM(rm)) );
3373 return delta;
sewardj948d48b2004-11-05 19:49:09 +00003374}
sewardj1813dbe2004-07-28 17:09:04 +00003375
3376
sewardj9a660ea2010-07-29 11:34:38 +00003377/* Generate an IR sequence to do a count-leading-zeroes operation on
3378 the supplied IRTemp, and return a new IRTemp holding the result.
3379 'ty' may be Ity_I16 or Ity_I32 only. In the case where the
3380 argument is zero, return the number of bits in the word (the
3381 natural semantics). */
3382static IRTemp gen_LZCNT ( IRType ty, IRTemp src )
3383{
3384 vassert(ty == Ity_I32 || ty == Ity_I16);
3385
3386 IRTemp src32 = newTemp(Ity_I32);
3387 assign(src32, widenUto32( mkexpr(src) ));
3388
3389 IRTemp src32x = newTemp(Ity_I32);
3390 assign(src32x,
3391 binop(Iop_Shl32, mkexpr(src32),
3392 mkU8(32 - 8 * sizeofIRType(ty))));
3393
3394 // Clz32 has undefined semantics when its input is zero, so
3395 // special-case around that.
3396 IRTemp res32 = newTemp(Ity_I32);
3397 assign(res32,
3398 IRExpr_Mux0X(
3399 unop(Iop_1Uto8,
3400 binop(Iop_CmpEQ32, mkexpr(src32x), mkU32(0))),
3401 unop(Iop_Clz32, mkexpr(src32x)),
3402 mkU32(8 * sizeofIRType(ty))
3403 ));
3404
3405 IRTemp res = newTemp(ty);
3406 assign(res, narrowTo(ty, mkexpr(res32)));
3407 return res;
3408}
3409
3410
sewardjd1725d12004-08-12 20:46:53 +00003411/*------------------------------------------------------------*/
sewardj464efa42004-11-19 22:17:29 +00003412/*--- ---*/
3413/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
3414/*--- ---*/
sewardjd1725d12004-08-12 20:46:53 +00003415/*------------------------------------------------------------*/
3416
sewardj207557a2004-08-27 12:00:18 +00003417/* --- Helper functions for dealing with the register stack. --- */
3418
sewardj893aada2004-11-29 19:57:54 +00003419/* --- Set the emulation-warning pseudo-register. --- */
3420
3421static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3422{
sewardjdd40fdf2006-12-24 02:20:24 +00003423 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj893aada2004-11-29 19:57:54 +00003424 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3425}
3426
sewardj17442fe2004-09-20 14:54:28 +00003427/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
sewardj207557a2004-08-27 12:00:18 +00003428
sewardj17442fe2004-09-20 14:54:28 +00003429static IRExpr* mkQNaN64 ( void )
sewardj207557a2004-08-27 12:00:18 +00003430{
sewardj17442fe2004-09-20 14:54:28 +00003431 /* QNaN is 0 2047 1 0(51times)
3432 == 0b 11111111111b 1 0(51times)
3433 == 0x7FF8 0000 0000 0000
3434 */
3435 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
sewardj207557a2004-08-27 12:00:18 +00003436}
3437
sewardj893aada2004-11-29 19:57:54 +00003438/* --------- Get/put the top-of-stack pointer. --------- */
sewardjd1725d12004-08-12 20:46:53 +00003439
3440static IRExpr* get_ftop ( void )
3441{
3442 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3443}
3444
sewardj207557a2004-08-27 12:00:18 +00003445static void put_ftop ( IRExpr* e )
sewardjd1725d12004-08-12 20:46:53 +00003446{
sewardjdd40fdf2006-12-24 02:20:24 +00003447 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj207557a2004-08-27 12:00:18 +00003448 stmt( IRStmt_Put( OFFB_FTOP, e ) );
sewardjd1725d12004-08-12 20:46:53 +00003449}
3450
sewardj893aada2004-11-29 19:57:54 +00003451/* --------- Get/put the C3210 bits. --------- */
sewardjbdc7d212004-09-09 02:46:40 +00003452
sewardjc4be80c2004-09-10 16:17:45 +00003453static IRExpr* get_C3210 ( void )
sewardjbdc7d212004-09-09 02:46:40 +00003454{
sewardjc4be80c2004-09-10 16:17:45 +00003455 return IRExpr_Get( OFFB_FC3210, Ity_I32 );
sewardjbdc7d212004-09-09 02:46:40 +00003456}
3457
sewardjc4be80c2004-09-10 16:17:45 +00003458static void put_C3210 ( IRExpr* e )
sewardjbdc7d212004-09-09 02:46:40 +00003459{
sewardjc4be80c2004-09-10 16:17:45 +00003460 stmt( IRStmt_Put( OFFB_FC3210, e ) );
sewardjbdc7d212004-09-09 02:46:40 +00003461}
sewardjd1725d12004-08-12 20:46:53 +00003462
sewardj893aada2004-11-29 19:57:54 +00003463/* --------- Get/put the FPU rounding mode. --------- */
sewardjd01a9632004-11-30 13:18:37 +00003464static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
sewardj8f3debf2004-09-08 23:42:23 +00003465{
sewardjd01a9632004-11-30 13:18:37 +00003466 return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
sewardj8f3debf2004-09-08 23:42:23 +00003467}
3468
sewardjd01a9632004-11-30 13:18:37 +00003469static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
sewardj8f3debf2004-09-08 23:42:23 +00003470{
sewardjd01a9632004-11-30 13:18:37 +00003471 stmt( IRStmt_Put( OFFB_FPROUND, e ) );
sewardj8f3debf2004-09-08 23:42:23 +00003472}
3473
3474
sewardj893aada2004-11-29 19:57:54 +00003475/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
sewardj8f3debf2004-09-08 23:42:23 +00003476/* Produces a value in 0 .. 3, which is encoded as per the type
sewardjd01a9632004-11-30 13:18:37 +00003477 IRRoundingMode. Since the guest_FPROUND value is also encoded as
3478 per IRRoundingMode, we merely need to get it and mask it for
3479 safety.
sewardj8f3debf2004-09-08 23:42:23 +00003480*/
3481static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3482{
sewardjd01a9632004-11-30 13:18:37 +00003483 return binop( Iop_And32, get_fpround(), mkU32(3) );
sewardj8f3debf2004-09-08 23:42:23 +00003484}
3485
sewardjf1b5b1a2006-02-03 22:54:17 +00003486static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
3487{
3488 return mkU32(Irrm_NEAREST);
3489}
3490
sewardj8f3debf2004-09-08 23:42:23 +00003491
sewardj207557a2004-08-27 12:00:18 +00003492/* --------- Get/set FP register tag bytes. --------- */
3493
sewardj207557a2004-08-27 12:00:18 +00003494/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3495
3496static void put_ST_TAG ( Int i, IRExpr* value )
3497{
sewardjdd40fdf2006-12-24 02:20:24 +00003498 IRRegArray* descr;
3499 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_I8);
3500 descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003501 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003502}
3503
3504/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
sewardjdb199622004-09-06 23:19:03 +00003505 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
sewardj207557a2004-08-27 12:00:18 +00003506
3507static IRExpr* get_ST_TAG ( Int i )
3508{
sewardjdd40fdf2006-12-24 02:20:24 +00003509 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003510 return IRExpr_GetI( descr, get_ftop(), i );
sewardj207557a2004-08-27 12:00:18 +00003511}
3512
3513
3514/* --------- Get/set FP registers. --------- */
3515
sewardj2d3f77c2004-09-22 23:49:09 +00003516/* Given i, and some expression e, emit 'ST(i) = e' and set the
3517 register's tag to indicate the register is full. The previous
3518 state of the register is not checked. */
sewardj207557a2004-08-27 12:00:18 +00003519
3520static void put_ST_UNCHECKED ( Int i, IRExpr* value )
sewardjd1725d12004-08-12 20:46:53 +00003521{
sewardjdd40fdf2006-12-24 02:20:24 +00003522 IRRegArray* descr;
3523 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_F64);
3524 descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003525 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003526 /* Mark the register as in-use. */
3527 put_ST_TAG(i, mkU8(1));
sewardjd1725d12004-08-12 20:46:53 +00003528}
3529
sewardj207557a2004-08-27 12:00:18 +00003530/* Given i, and some expression e, emit
3531 ST(i) = is_full(i) ? NaN : e
3532 and set the tag accordingly.
3533*/
3534
3535static void put_ST ( Int i, IRExpr* value )
3536{
3537 put_ST_UNCHECKED( i,
sewardjdb199622004-09-06 23:19:03 +00003538 IRExpr_Mux0X( get_ST_TAG(i),
3539 /* 0 means empty */
3540 value,
3541 /* non-0 means full */
sewardj17442fe2004-09-20 14:54:28 +00003542 mkQNaN64()
sewardj207557a2004-08-27 12:00:18 +00003543 )
3544 );
3545}
3546
3547
sewardjd1725d12004-08-12 20:46:53 +00003548/* Given i, generate an expression yielding 'ST(i)'. */
3549
sewardj207557a2004-08-27 12:00:18 +00003550static IRExpr* get_ST_UNCHECKED ( Int i )
sewardjd1725d12004-08-12 20:46:53 +00003551{
sewardjdd40fdf2006-12-24 02:20:24 +00003552 IRRegArray* descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003553 return IRExpr_GetI( descr, get_ftop(), i );
sewardjd1725d12004-08-12 20:46:53 +00003554}
3555
sewardjc4be80c2004-09-10 16:17:45 +00003556
sewardj207557a2004-08-27 12:00:18 +00003557/* Given i, generate an expression yielding
3558 is_full(i) ? ST(i) : NaN
3559*/
3560
3561static IRExpr* get_ST ( Int i )
3562{
3563 return
3564 IRExpr_Mux0X( get_ST_TAG(i),
3565 /* 0 means empty */
sewardj17442fe2004-09-20 14:54:28 +00003566 mkQNaN64(),
sewardj207557a2004-08-27 12:00:18 +00003567 /* non-0 means full */
3568 get_ST_UNCHECKED(i));
3569}
3570
3571
sewardjd1725d12004-08-12 20:46:53 +00003572/* Adjust FTOP downwards by one register. */
3573
sewardj207557a2004-08-27 12:00:18 +00003574static void fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003575{
sewardj2d3f77c2004-09-22 23:49:09 +00003576 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
sewardjd1725d12004-08-12 20:46:53 +00003577}
3578
sewardj207557a2004-08-27 12:00:18 +00003579/* Adjust FTOP upwards by one register, and mark the vacated register
3580 as empty. */
sewardja58ea662004-08-15 03:12:41 +00003581
sewardj207557a2004-08-27 12:00:18 +00003582static void fp_pop ( void )
sewardja58ea662004-08-15 03:12:41 +00003583{
sewardjdb199622004-09-06 23:19:03 +00003584 put_ST_TAG(0, mkU8(0));
sewardj2d3f77c2004-09-22 23:49:09 +00003585 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
sewardja58ea662004-08-15 03:12:41 +00003586}
3587
sewardj3f61ddb2004-10-16 20:51:05 +00003588/* Clear the C2 bit of the FPU status register, for
3589 sin/cos/tan/sincos. */
3590
3591static void clear_C2 ( void )
3592{
sewardj67e002d2004-12-02 18:16:33 +00003593 put_C3210( binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2)) );
sewardj3f61ddb2004-10-16 20:51:05 +00003594}
3595
sewardjd24931d2005-03-20 12:51:39 +00003596/* Invent a plausible-looking FPU status word value:
3597 ((ftop & 7) << 11) | (c3210 & 0x4700)
3598 */
3599static IRExpr* get_FPU_sw ( void )
3600{
3601 return
3602 unop(Iop_32to16,
3603 binop(Iop_Or32,
3604 binop(Iop_Shl32,
3605 binop(Iop_And32, get_ftop(), mkU32(7)),
3606 mkU8(11)),
3607 binop(Iop_And32, get_C3210(), mkU32(0x4700))
3608 ));
3609}
3610
sewardj3f61ddb2004-10-16 20:51:05 +00003611
sewardj207557a2004-08-27 12:00:18 +00003612/* ------------------------------------------------------- */
3613/* Given all that stack-mangling junk, we can now go ahead
3614 and describe FP instructions.
3615*/
3616
sewardj3fd5e572004-09-09 22:43:51 +00003617/* ST(0) = ST(0) `op` mem64/32(addr)
sewardj207557a2004-08-27 12:00:18 +00003618 Need to check ST(0)'s tag on read, but not on write.
3619*/
sewardja58ea662004-08-15 03:12:41 +00003620static
sewardj2d49b432005-02-01 00:37:06 +00003621void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardja58ea662004-08-15 03:12:41 +00003622 IROp op, Bool dbl )
3623{
sewardj33dd31b2005-01-08 18:17:32 +00003624 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardja58ea662004-08-15 03:12:41 +00003625 if (dbl) {
sewardj3fd5e572004-09-09 22:43:51 +00003626 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003627 triop( op,
3628 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003629 get_ST(0),
3630 loadLE(Ity_F64,mkexpr(addr))
3631 ));
sewardja58ea662004-08-15 03:12:41 +00003632 } else {
sewardj3fd5e572004-09-09 22:43:51 +00003633 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003634 triop( op,
3635 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003636 get_ST(0),
3637 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3638 ));
3639 }
3640}
3641
3642
3643/* ST(0) = mem64/32(addr) `op` ST(0)
3644 Need to check ST(0)'s tag on read, but not on write.
3645*/
3646static
sewardj2d49b432005-02-01 00:37:06 +00003647void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardj883b00b2004-09-11 09:30:24 +00003648 IROp op, Bool dbl )
sewardj3fd5e572004-09-09 22:43:51 +00003649{
sewardj33dd31b2005-01-08 18:17:32 +00003650 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardj3fd5e572004-09-09 22:43:51 +00003651 if (dbl) {
3652 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003653 triop( op,
3654 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003655 loadLE(Ity_F64,mkexpr(addr)),
3656 get_ST(0)
3657 ));
3658 } else {
3659 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003660 triop( op,
3661 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003662 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3663 get_ST(0)
3664 ));
sewardja58ea662004-08-15 03:12:41 +00003665 }
3666}
3667
sewardjd1725d12004-08-12 20:46:53 +00003668
sewardjdb199622004-09-06 23:19:03 +00003669/* ST(dst) = ST(dst) `op` ST(src).
3670 Check dst and src tags when reading but not on write.
3671*/
3672static
sewardj2d49b432005-02-01 00:37:06 +00003673void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardjbdc7d212004-09-09 02:46:40 +00003674 Bool pop_after )
sewardjdb199622004-09-06 23:19:03 +00003675{
sewardj2d49b432005-02-01 00:37:06 +00003676 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3677 (Int)st_src, (Int)st_dst );
sewardjdb199622004-09-06 23:19:03 +00003678 put_ST_UNCHECKED(
3679 st_dst,
sewardjf1b5b1a2006-02-03 22:54:17 +00003680 triop( op,
3681 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3682 get_ST(st_dst),
3683 get_ST(st_src) )
sewardjdb199622004-09-06 23:19:03 +00003684 );
sewardjbdc7d212004-09-09 02:46:40 +00003685 if (pop_after)
3686 fp_pop();
3687}
3688
3689/* ST(dst) = ST(src) `op` ST(dst).
3690 Check dst and src tags when reading but not on write.
3691*/
3692static
sewardj2d49b432005-02-01 00:37:06 +00003693void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardj883b00b2004-09-11 09:30:24 +00003694 Bool pop_after )
sewardjbdc7d212004-09-09 02:46:40 +00003695{
sewardj2d49b432005-02-01 00:37:06 +00003696 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3697 (Int)st_src, (Int)st_dst );
sewardjbdc7d212004-09-09 02:46:40 +00003698 put_ST_UNCHECKED(
3699 st_dst,
sewardjf1b5b1a2006-02-03 22:54:17 +00003700 triop( op,
3701 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3702 get_ST(st_src),
3703 get_ST(st_dst) )
sewardjbdc7d212004-09-09 02:46:40 +00003704 );
3705 if (pop_after)
3706 fp_pop();
sewardjdb199622004-09-06 23:19:03 +00003707}
3708
sewardj8308aad2004-09-12 11:09:54 +00003709/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3710static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3711{
sewardj2d49b432005-02-01 00:37:06 +00003712 DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", (Int)i );
sewardj8308aad2004-09-12 11:09:54 +00003713 /* This is a bit of a hack (and isn't really right). It sets
3714 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3715 documentation implies A and S are unchanged.
3716 */
sewardjfeeb8a82004-11-30 12:30:11 +00003717 /* It's also fishy in that it is used both for COMIP and
3718 UCOMIP, and they aren't the same (although similar). */
sewardj2a9ad022004-11-25 02:46:58 +00003719 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00003720 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
3721 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj8308aad2004-09-12 11:09:54 +00003722 binop( Iop_And32,
3723 binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3724 mkU32(0x45)
3725 )));
sewardja3b7e3a2005-04-05 01:54:19 +00003726 /* Set NDEP even though it isn't used. This makes redundant-PUT
3727 elimination of previous stores to this field work better. */
3728 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj8308aad2004-09-12 11:09:54 +00003729 if (pop_after)
3730 fp_pop();
3731}
3732
sewardjdb199622004-09-06 23:19:03 +00003733
sewardjd1725d12004-08-12 20:46:53 +00003734static
sewardj52d04912005-07-03 00:52:48 +00003735UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
sewardjd1725d12004-08-12 20:46:53 +00003736{
sewardja58ea662004-08-15 03:12:41 +00003737 Int len;
3738 UInt r_src, r_dst;
sewardjc9a43662004-11-30 18:51:59 +00003739 HChar dis_buf[50];
sewardj89cd0932004-09-08 18:23:25 +00003740 IRTemp t1, t2;
sewardjd1725d12004-08-12 20:46:53 +00003741
3742 /* On entry, delta points at the second byte of the insn (the modrm
3743 byte).*/
3744 UChar first_opcode = getIByte(delta-1);
3745 UChar modrm = getIByte(delta+0);
3746
3747 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3748
3749 if (first_opcode == 0xD8) {
sewardjdb199622004-09-06 23:19:03 +00003750 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003751
3752 /* bits 5,4,3 are an opcode extension, and the modRM also
3753 specifies an address. */
3754 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3755 delta += len;
3756
3757 switch (gregOfRM(modrm)) {
3758
sewardj3fd5e572004-09-09 22:43:51 +00003759 case 0: /* FADD single-real */
3760 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3761 break;
3762
sewardj89cd0932004-09-08 18:23:25 +00003763 case 1: /* FMUL single-real */
3764 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3765 break;
3766
sewardj7ca37d92004-10-25 02:58:30 +00003767 case 2: /* FCOM single-real */
3768 DIP("fcoms %s\n", dis_buf);
3769 /* This forces C1 to zero, which isn't right. */
3770 put_C3210(
3771 binop( Iop_And32,
3772 binop(Iop_Shl32,
3773 binop(Iop_CmpF64,
3774 get_ST(0),
3775 unop(Iop_F32toF64,
3776 loadLE(Ity_F32,mkexpr(addr)))),
3777 mkU8(8)),
3778 mkU32(0x4500)
3779 ));
3780 break;
3781
3782 case 3: /* FCOMP single-real */
sewardje166ed02004-10-25 02:27:01 +00003783 DIP("fcomps %s\n", dis_buf);
3784 /* This forces C1 to zero, which isn't right. */
3785 put_C3210(
3786 binop( Iop_And32,
3787 binop(Iop_Shl32,
3788 binop(Iop_CmpF64,
3789 get_ST(0),
3790 unop(Iop_F32toF64,
3791 loadLE(Ity_F32,mkexpr(addr)))),
3792 mkU8(8)),
3793 mkU32(0x4500)
3794 ));
3795 fp_pop();
3796 break;
3797
sewardj588ea762004-09-10 18:56:32 +00003798 case 4: /* FSUB single-real */
3799 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3800 break;
3801
3802 case 5: /* FSUBR single-real */
3803 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3804 break;
3805
sewardjbdc7d212004-09-09 02:46:40 +00003806 case 6: /* FDIV single-real */
3807 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3808 break;
3809
sewardj8308aad2004-09-12 11:09:54 +00003810 case 7: /* FDIVR single-real */
3811 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3812 break;
3813
sewardj89cd0932004-09-08 18:23:25 +00003814 default:
3815 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3816 vex_printf("first_opcode == 0xD8\n");
3817 goto decode_fail;
3818 }
sewardjdb199622004-09-06 23:19:03 +00003819 } else {
3820 delta++;
3821 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003822
sewardjdb199622004-09-06 23:19:03 +00003823 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003824 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
sewardjdb199622004-09-06 23:19:03 +00003825 break;
sewardj89cd0932004-09-08 18:23:25 +00003826
sewardj3fd5e572004-09-09 22:43:51 +00003827 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3828 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3829 break;
3830
sewardje166ed02004-10-25 02:27:01 +00003831 /* Dunno if this is right */
3832 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3833 r_dst = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00003834 DIP("fcom %%st(0),%%st(%d)\n", (Int)r_dst);
sewardje166ed02004-10-25 02:27:01 +00003835 /* This forces C1 to zero, which isn't right. */
3836 put_C3210(
3837 binop( Iop_And32,
3838 binop(Iop_Shl32,
3839 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3840 mkU8(8)),
3841 mkU32(0x4500)
3842 ));
3843 break;
sewardj2d49b432005-02-01 00:37:06 +00003844
sewardj98169c52004-10-24 13:11:39 +00003845 /* Dunno if this is right */
3846 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3847 r_dst = (UInt)modrm - 0xD8;
sewardj2d49b432005-02-01 00:37:06 +00003848 DIP("fcomp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj98169c52004-10-24 13:11:39 +00003849 /* This forces C1 to zero, which isn't right. */
3850 put_C3210(
3851 binop( Iop_And32,
3852 binop(Iop_Shl32,
3853 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3854 mkU8(8)),
3855 mkU32(0x4500)
3856 ));
3857 fp_pop();
3858 break;
sewardj2d49b432005-02-01 00:37:06 +00003859
sewardj89cd0932004-09-08 18:23:25 +00003860 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003861 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
sewardj89cd0932004-09-08 18:23:25 +00003862 break;
3863
sewardj8308aad2004-09-12 11:09:54 +00003864 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3865 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3866 break;
3867
sewardj3fd5e572004-09-09 22:43:51 +00003868 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3869 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3870 break;
3871
3872 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3873 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3874 break;
3875
sewardjdb199622004-09-06 23:19:03 +00003876 default:
3877 goto decode_fail;
3878 }
3879 }
sewardjd1725d12004-08-12 20:46:53 +00003880 }
3881
3882 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3883 else
3884 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003885 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003886
3887 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00003888 specifies an address. */
sewardj89cd0932004-09-08 18:23:25 +00003889 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3890 delta += len;
3891
3892 switch (gregOfRM(modrm)) {
3893
3894 case 0: /* FLD single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003895 DIP("flds %s\n", dis_buf);
sewardj89cd0932004-09-08 18:23:25 +00003896 fp_push();
3897 put_ST(0, unop(Iop_F32toF64,
sewardj8f3debf2004-09-08 23:42:23 +00003898 loadLE(Ity_F32, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00003899 break;
3900
sewardj588ea762004-09-10 18:56:32 +00003901 case 2: /* FST single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003902 DIP("fsts %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003903 storeLE(mkexpr(addr),
3904 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj588ea762004-09-10 18:56:32 +00003905 break;
3906
sewardj89cd0932004-09-08 18:23:25 +00003907 case 3: /* FSTP single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003908 DIP("fstps %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003909 storeLE(mkexpr(addr),
3910 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj5bd4d162004-11-10 13:02:48 +00003911 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00003912 break;
3913
sewardjd24931d2005-03-20 12:51:39 +00003914 case 4: { /* FLDENV m28 */
sewardj7df596b2004-12-06 14:29:12 +00003915 /* Uses dirty helper:
sewardj4017a3b2005-06-13 12:17:27 +00003916 VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00003917 IRTemp ew = newTemp(Ity_I32);
3918 IRDirty* d = unsafeIRDirty_0_N (
3919 0/*regparms*/,
3920 "x86g_dirtyhelper_FLDENV",
3921 &x86g_dirtyhelper_FLDENV,
3922 mkIRExprVec_1( mkexpr(addr) )
3923 );
3924 d->needsBBP = True;
3925 d->tmp = ew;
3926 /* declare we're reading memory */
3927 d->mFx = Ifx_Read;
3928 d->mAddr = mkexpr(addr);
3929 d->mSize = 28;
3930
3931 /* declare we're writing guest state */
sewardj46813fc2005-06-13 12:33:36 +00003932 d->nFxState = 4;
sewardj7df596b2004-12-06 14:29:12 +00003933
3934 d->fxState[0].fx = Ifx_Write;
3935 d->fxState[0].offset = OFFB_FTOP;
3936 d->fxState[0].size = sizeof(UInt);
3937
3938 d->fxState[1].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003939 d->fxState[1].offset = OFFB_FPTAGS;
3940 d->fxState[1].size = 8 * sizeof(UChar);
sewardj7df596b2004-12-06 14:29:12 +00003941
3942 d->fxState[2].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003943 d->fxState[2].offset = OFFB_FPROUND;
3944 d->fxState[2].size = sizeof(UInt);
sewardj7df596b2004-12-06 14:29:12 +00003945
3946 d->fxState[3].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003947 d->fxState[3].offset = OFFB_FC3210;
sewardj7df596b2004-12-06 14:29:12 +00003948 d->fxState[3].size = sizeof(UInt);
3949
sewardj7df596b2004-12-06 14:29:12 +00003950 stmt( IRStmt_Dirty(d) );
3951
3952 /* ew contains any emulation warning we may need to
3953 issue. If needed, side-exit to the next insn,
3954 reporting the warning, so that Valgrind's dispatcher
3955 sees the warning. */
3956 put_emwarn( mkexpr(ew) );
3957 stmt(
3958 IRStmt_Exit(
3959 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3960 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00003961 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj7df596b2004-12-06 14:29:12 +00003962 )
3963 );
3964
sewardj33dd31b2005-01-08 18:17:32 +00003965 DIP("fldenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00003966 break;
3967 }
3968
sewardj893aada2004-11-29 19:57:54 +00003969 case 5: {/* FLDCW */
3970 /* The only thing we observe in the control word is the
sewardjd01a9632004-11-30 13:18:37 +00003971 rounding mode. Therefore, pass the 16-bit value
3972 (x87 native-format control word) to a clean helper,
3973 getting back a 64-bit value, the lower half of which
3974 is the FPROUND value to store, and the upper half of
3975 which is the emulation-warning token which may be
3976 generated.
sewardj893aada2004-11-29 19:57:54 +00003977 */
3978 /* ULong x86h_check_fldcw ( UInt ); */
3979 IRTemp t64 = newTemp(Ity_I64);
3980 IRTemp ew = newTemp(Ity_I32);
sewardj33dd31b2005-01-08 18:17:32 +00003981 DIP("fldcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00003982 assign( t64, mkIRExprCCall(
3983 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00003984 "x86g_check_fldcw",
3985 &x86g_check_fldcw,
sewardj893aada2004-11-29 19:57:54 +00003986 mkIRExprVec_1(
3987 unop( Iop_16Uto32,
3988 loadLE(Ity_I16, mkexpr(addr)))
3989 )
3990 )
3991 );
3992
sewardjd01a9632004-11-30 13:18:37 +00003993 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
sewardj893aada2004-11-29 19:57:54 +00003994 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
3995 put_emwarn( mkexpr(ew) );
3996 /* Finally, if an emulation warning was reported,
3997 side-exit to the next insn, reporting the warning,
3998 so that Valgrind's dispatcher sees the warning. */
3999 stmt(
4000 IRStmt_Exit(
4001 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4002 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004003 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj893aada2004-11-29 19:57:54 +00004004 )
4005 );
sewardj89cd0932004-09-08 18:23:25 +00004006 break;
sewardj893aada2004-11-29 19:57:54 +00004007 }
sewardj89cd0932004-09-08 18:23:25 +00004008
sewardj7df596b2004-12-06 14:29:12 +00004009 case 6: { /* FNSTENV m28 */
4010 /* Uses dirty helper:
sewardj4017a3b2005-06-13 12:17:27 +00004011 void x86g_do_FSTENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00004012 IRDirty* d = unsafeIRDirty_0_N (
4013 0/*regparms*/,
4014 "x86g_dirtyhelper_FSTENV",
4015 &x86g_dirtyhelper_FSTENV,
4016 mkIRExprVec_1( mkexpr(addr) )
4017 );
4018 d->needsBBP = True;
4019 /* declare we're writing memory */
4020 d->mFx = Ifx_Write;
4021 d->mAddr = mkexpr(addr);
4022 d->mSize = 28;
4023
4024 /* declare we're reading guest state */
4025 d->nFxState = 4;
4026
4027 d->fxState[0].fx = Ifx_Read;
4028 d->fxState[0].offset = OFFB_FTOP;
4029 d->fxState[0].size = sizeof(UInt);
4030
4031 d->fxState[1].fx = Ifx_Read;
4032 d->fxState[1].offset = OFFB_FPTAGS;
4033 d->fxState[1].size = 8 * sizeof(UChar);
4034
4035 d->fxState[2].fx = Ifx_Read;
4036 d->fxState[2].offset = OFFB_FPROUND;
4037 d->fxState[2].size = sizeof(UInt);
4038
4039 d->fxState[3].fx = Ifx_Read;
4040 d->fxState[3].offset = OFFB_FC3210;
4041 d->fxState[3].size = sizeof(UInt);
4042
4043 stmt( IRStmt_Dirty(d) );
4044
sewardj33dd31b2005-01-08 18:17:32 +00004045 DIP("fnstenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00004046 break;
4047 }
4048
sewardj588ea762004-09-10 18:56:32 +00004049 case 7: /* FNSTCW */
sewardj893aada2004-11-29 19:57:54 +00004050 /* Fake up a native x87 FPU control word. The only
sewardjd01a9632004-11-30 13:18:37 +00004051 thing it depends on is FPROUND[1:0], so call a clean
sewardj893aada2004-11-29 19:57:54 +00004052 helper to cook it up. */
sewardjd01a9632004-11-30 13:18:37 +00004053 /* UInt x86h_create_fpucw ( UInt fpround ) */
sewardj33dd31b2005-01-08 18:17:32 +00004054 DIP("fnstcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00004055 storeLE(
4056 mkexpr(addr),
4057 unop( Iop_32to16,
4058 mkIRExprCCall(
4059 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00004060 "x86g_create_fpucw", &x86g_create_fpucw,
sewardjd01a9632004-11-30 13:18:37 +00004061 mkIRExprVec_1( get_fpround() )
sewardj893aada2004-11-29 19:57:54 +00004062 )
4063 )
4064 );
sewardj89cd0932004-09-08 18:23:25 +00004065 break;
4066
4067 default:
4068 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4069 vex_printf("first_opcode == 0xD9\n");
4070 goto decode_fail;
4071 }
4072
sewardjbb53f8c2004-08-14 11:50:01 +00004073 } else {
4074 delta++;
4075 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00004076
sewardjbb53f8c2004-08-14 11:50:01 +00004077 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00004078 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00004079 DIP("fld %%st(%d)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004080 t1 = newTemp(Ity_F64);
4081 assign(t1, get_ST(r_src));
4082 fp_push();
4083 put_ST(0, mkexpr(t1));
sewardjbb53f8c2004-08-14 11:50:01 +00004084 break;
4085
sewardj89cd0932004-09-08 18:23:25 +00004086 case 0xC8 ... 0xCF: /* FXCH %st(?) */
4087 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00004088 DIP("fxch %%st(%d)\n", (Int)r_src);
sewardj89cd0932004-09-08 18:23:25 +00004089 t1 = newTemp(Ity_F64);
4090 t2 = newTemp(Ity_F64);
4091 assign(t1, get_ST(0));
4092 assign(t2, get_ST(r_src));
4093 put_ST_UNCHECKED(0, mkexpr(t2));
4094 put_ST_UNCHECKED(r_src, mkexpr(t1));
4095 break;
4096
sewardjcfded9a2004-09-09 11:44:16 +00004097 case 0xE0: /* FCHS */
4098 DIP("fchs\n");
4099 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4100 break;
4101
sewardj883b00b2004-09-11 09:30:24 +00004102 case 0xE1: /* FABS */
4103 DIP("fabs\n");
4104 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4105 break;
sewardjc4be80c2004-09-10 16:17:45 +00004106
sewardj1c318772005-03-19 14:27:04 +00004107 case 0xE4: /* FTST */
4108 DIP("ftst\n");
4109 /* This forces C1 to zero, which isn't right. */
4110 /* Well, in fact the Intel docs say (bizarrely): "C1 is
4111 set to 0 if stack underflow occurred; otherwise, set
4112 to 0" which is pretty nonsensical. I guess it's a
4113 typo. */
4114 put_C3210(
4115 binop( Iop_And32,
4116 binop(Iop_Shl32,
4117 binop(Iop_CmpF64,
4118 get_ST(0),
4119 IRExpr_Const(IRConst_F64i(0x0ULL))),
4120 mkU8(8)),
4121 mkU32(0x4500)
4122 ));
4123 break;
4124
sewardj883b00b2004-09-11 09:30:24 +00004125 case 0xE5: { /* FXAM */
4126 /* This is an interesting one. It examines %st(0),
4127 regardless of whether the tag says it's empty or not.
4128 Here, just pass both the tag (in our format) and the
4129 value (as a double, actually a ULong) to a helper
4130 function. */
sewardjf9655262004-10-31 20:02:16 +00004131 IRExpr** args
4132 = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
4133 unop(Iop_ReinterpF64asI64,
4134 get_ST_UNCHECKED(0)) );
4135 put_C3210(mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00004136 Ity_I32,
sewardjf9655262004-10-31 20:02:16 +00004137 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00004138 "x86g_calculate_FXAM", &x86g_calculate_FXAM,
sewardj8ea867b2004-10-30 19:03:02 +00004139 args
4140 ));
sewardj33dd31b2005-01-08 18:17:32 +00004141 DIP("fxam\n");
sewardj883b00b2004-09-11 09:30:24 +00004142 break;
4143 }
4144
4145 case 0xE8: /* FLD1 */
sewardj33dd31b2005-01-08 18:17:32 +00004146 DIP("fld1\n");
sewardjce646f22004-08-31 23:55:54 +00004147 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004148 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
4149 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
sewardjce646f22004-08-31 23:55:54 +00004150 break;
4151
sewardj37158712004-10-15 21:23:12 +00004152 case 0xE9: /* FLDL2T */
sewardj33dd31b2005-01-08 18:17:32 +00004153 DIP("fldl2t\n");
sewardj37158712004-10-15 21:23:12 +00004154 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004155 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
4156 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
sewardj37158712004-10-15 21:23:12 +00004157 break;
4158
sewardj8308aad2004-09-12 11:09:54 +00004159 case 0xEA: /* FLDL2E */
sewardj33dd31b2005-01-08 18:17:32 +00004160 DIP("fldl2e\n");
sewardj8308aad2004-09-12 11:09:54 +00004161 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004162 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
4163 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
sewardj8308aad2004-09-12 11:09:54 +00004164 break;
4165
sewardja0d48d62004-09-20 21:19:03 +00004166 case 0xEB: /* FLDPI */
sewardj33dd31b2005-01-08 18:17:32 +00004167 DIP("fldpi\n");
sewardja0d48d62004-09-20 21:19:03 +00004168 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004169 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
4170 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
sewardja0d48d62004-09-20 21:19:03 +00004171 break;
4172
sewardjdb199622004-09-06 23:19:03 +00004173 case 0xEC: /* FLDLG2 */
sewardj33dd31b2005-01-08 18:17:32 +00004174 DIP("fldlg2\n");
sewardjdb199622004-09-06 23:19:03 +00004175 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004176 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
4177 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
sewardjdb199622004-09-06 23:19:03 +00004178 break;
4179
4180 case 0xED: /* FLDLN2 */
sewardj33dd31b2005-01-08 18:17:32 +00004181 DIP("fldln2\n");
sewardjdb199622004-09-06 23:19:03 +00004182 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004183 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
4184 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
sewardjdb199622004-09-06 23:19:03 +00004185 break;
4186
sewardja58ea662004-08-15 03:12:41 +00004187 case 0xEE: /* FLDZ */
sewardj33dd31b2005-01-08 18:17:32 +00004188 DIP("fldz\n");
sewardj207557a2004-08-27 12:00:18 +00004189 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004190 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
4191 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
sewardja58ea662004-08-15 03:12:41 +00004192 break;
4193
sewardj06c32a02004-09-12 12:07:34 +00004194 case 0xF0: /* F2XM1 */
4195 DIP("f2xm1\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004196 put_ST_UNCHECKED(0,
4197 binop(Iop_2xm1F64,
4198 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4199 get_ST(0)));
sewardj06c32a02004-09-12 12:07:34 +00004200 break;
4201
sewardj52ace3e2004-09-11 17:10:08 +00004202 case 0xF1: /* FYL2X */
4203 DIP("fyl2x\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004204 put_ST_UNCHECKED(1,
4205 triop(Iop_Yl2xF64,
4206 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4207 get_ST(1),
4208 get_ST(0)));
sewardj52ace3e2004-09-11 17:10:08 +00004209 fp_pop();
4210 break;
4211
sewardj99016a72004-10-15 22:09:17 +00004212 case 0xF2: /* FPTAN */
4213 DIP("ftan\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004214 put_ST_UNCHECKED(0,
4215 binop(Iop_TanF64,
4216 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4217 get_ST(0)));
sewardj99016a72004-10-15 22:09:17 +00004218 fp_push();
4219 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004220 clear_C2(); /* HACK */
sewardj99016a72004-10-15 22:09:17 +00004221 break;
4222
sewardjcfded9a2004-09-09 11:44:16 +00004223 case 0xF3: /* FPATAN */
4224 DIP("fpatan\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004225 put_ST_UNCHECKED(1,
4226 triop(Iop_AtanF64,
4227 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4228 get_ST(1),
4229 get_ST(0)));
sewardjcfded9a2004-09-09 11:44:16 +00004230 fp_pop();
4231 break;
4232
sewardjf1b5b1a2006-02-03 22:54:17 +00004233 case 0xF4: { /* FXTRACT */
sewardjfda10af2005-10-03 01:02:40 +00004234 IRTemp argF = newTemp(Ity_F64);
4235 IRTemp sigF = newTemp(Ity_F64);
4236 IRTemp expF = newTemp(Ity_F64);
4237 IRTemp argI = newTemp(Ity_I64);
4238 IRTemp sigI = newTemp(Ity_I64);
4239 IRTemp expI = newTemp(Ity_I64);
4240 DIP("fxtract\n");
4241 assign( argF, get_ST(0) );
4242 assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
4243 assign( sigI,
sewardj879cee02006-03-07 01:15:50 +00004244 mkIRExprCCall(
4245 Ity_I64, 0/*regparms*/,
4246 "x86amd64g_calculate_FXTRACT",
4247 &x86amd64g_calculate_FXTRACT,
4248 mkIRExprVec_2( mkexpr(argI),
4249 mkIRExpr_HWord(0)/*sig*/ ))
4250 );
sewardjfda10af2005-10-03 01:02:40 +00004251 assign( expI,
sewardj879cee02006-03-07 01:15:50 +00004252 mkIRExprCCall(
4253 Ity_I64, 0/*regparms*/,
4254 "x86amd64g_calculate_FXTRACT",
4255 &x86amd64g_calculate_FXTRACT,
4256 mkIRExprVec_2( mkexpr(argI),
4257 mkIRExpr_HWord(1)/*exp*/ ))
4258 );
sewardjfda10af2005-10-03 01:02:40 +00004259 assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
4260 assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
4261 /* exponent */
4262 put_ST_UNCHECKED(0, mkexpr(expF) );
4263 fp_push();
4264 /* significand */
4265 put_ST(0, mkexpr(sigF) );
4266 break;
4267 }
4268
sewardj442d0be2004-10-15 22:57:13 +00004269 case 0xF5: { /* FPREM1 -- IEEE compliant */
4270 IRTemp a1 = newTemp(Ity_F64);
4271 IRTemp a2 = newTemp(Ity_F64);
4272 DIP("fprem1\n");
4273 /* Do FPREM1 twice, once to get the remainder, and once
4274 to get the C3210 flag values. */
4275 assign( a1, get_ST(0) );
4276 assign( a2, get_ST(1) );
sewardjf47286e2006-02-04 15:20:13 +00004277 put_ST_UNCHECKED(0,
4278 triop(Iop_PRem1F64,
4279 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4280 mkexpr(a1),
4281 mkexpr(a2)));
4282 put_C3210(
4283 triop(Iop_PRem1C3210F64,
4284 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4285 mkexpr(a1),
4286 mkexpr(a2)) );
sewardj442d0be2004-10-15 22:57:13 +00004287 break;
4288 }
4289
sewardjfeeb8a82004-11-30 12:30:11 +00004290 case 0xF7: /* FINCSTP */
4291 DIP("fprem\n");
4292 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4293 break;
4294
sewardj46de4072004-09-11 19:23:24 +00004295 case 0xF8: { /* FPREM -- not IEEE compliant */
4296 IRTemp a1 = newTemp(Ity_F64);
4297 IRTemp a2 = newTemp(Ity_F64);
4298 DIP("fprem\n");
4299 /* Do FPREM twice, once to get the remainder, and once
4300 to get the C3210 flag values. */
4301 assign( a1, get_ST(0) );
4302 assign( a2, get_ST(1) );
sewardjf47286e2006-02-04 15:20:13 +00004303 put_ST_UNCHECKED(0,
4304 triop(Iop_PRemF64,
4305 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4306 mkexpr(a1),
4307 mkexpr(a2)));
4308 put_C3210(
4309 triop(Iop_PRemC3210F64,
4310 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4311 mkexpr(a1),
4312 mkexpr(a2)) );
sewardj46de4072004-09-11 19:23:24 +00004313 break;
4314 }
4315
sewardj8308aad2004-09-12 11:09:54 +00004316 case 0xF9: /* FYL2XP1 */
4317 DIP("fyl2xp1\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004318 put_ST_UNCHECKED(1,
4319 triop(Iop_Yl2xp1F64,
4320 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4321 get_ST(1),
4322 get_ST(0)));
sewardj8308aad2004-09-12 11:09:54 +00004323 fp_pop();
4324 break;
4325
sewardjc4be80c2004-09-10 16:17:45 +00004326 case 0xFA: /* FSQRT */
4327 DIP("fsqrt\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004328 put_ST_UNCHECKED(0,
4329 binop(Iop_SqrtF64,
4330 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4331 get_ST(0)));
sewardjc4be80c2004-09-10 16:17:45 +00004332 break;
4333
sewardj519d66f2004-12-15 11:57:58 +00004334 case 0xFB: { /* FSINCOS */
4335 IRTemp a1 = newTemp(Ity_F64);
4336 assign( a1, get_ST(0) );
4337 DIP("fsincos\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004338 put_ST_UNCHECKED(0,
4339 binop(Iop_SinF64,
4340 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4341 mkexpr(a1)));
sewardj519d66f2004-12-15 11:57:58 +00004342 fp_push();
sewardjf1b5b1a2006-02-03 22:54:17 +00004343 put_ST(0,
4344 binop(Iop_CosF64,
4345 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4346 mkexpr(a1)));
sewardj88a69242005-04-01 20:19:20 +00004347 clear_C2(); /* HACK */
sewardj519d66f2004-12-15 11:57:58 +00004348 break;
4349 }
4350
sewardje6709112004-09-10 18:37:18 +00004351 case 0xFC: /* FRNDINT */
4352 DIP("frndint\n");
4353 put_ST_UNCHECKED(0,
sewardjb183b852006-02-03 16:08:03 +00004354 binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
sewardje6709112004-09-10 18:37:18 +00004355 break;
4356
sewardj06c32a02004-09-12 12:07:34 +00004357 case 0xFD: /* FSCALE */
4358 DIP("fscale\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004359 put_ST_UNCHECKED(0,
4360 triop(Iop_ScaleF64,
4361 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4362 get_ST(0),
4363 get_ST(1)));
sewardj06c32a02004-09-12 12:07:34 +00004364 break;
4365
sewardjcfded9a2004-09-09 11:44:16 +00004366 case 0xFE: /* FSIN */
4367 DIP("fsin\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004368 put_ST_UNCHECKED(0,
4369 binop(Iop_SinF64,
4370 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4371 get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004372 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00004373 break;
4374
4375 case 0xFF: /* FCOS */
4376 DIP("fcos\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004377 put_ST_UNCHECKED(0,
4378 binop(Iop_CosF64,
4379 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4380 get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004381 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00004382 break;
4383
sewardjbb53f8c2004-08-14 11:50:01 +00004384 default:
4385 goto decode_fail;
4386 }
4387 }
sewardjd1725d12004-08-12 20:46:53 +00004388 }
4389
4390 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4391 else
4392 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00004393
4394 if (modrm < 0xC0) {
4395
sewardjfeeb8a82004-11-30 12:30:11 +00004396 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjbb53f8c2004-08-14 11:50:01 +00004397 specifies an address. */
sewardjce646f22004-08-31 23:55:54 +00004398 IROp fop;
sewardjbb53f8c2004-08-14 11:50:01 +00004399 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4400 delta += len;
sewardjbb53f8c2004-08-14 11:50:01 +00004401 switch (gregOfRM(modrm)) {
sewardjce646f22004-08-31 23:55:54 +00004402
sewardjdb199622004-09-06 23:19:03 +00004403 case 0: /* FIADD m32int */ /* ST(0) += m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004404 DIP("fiaddl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004405 fop = Iop_AddF64;
4406 goto do_fop_m32;
sewardjdb199622004-09-06 23:19:03 +00004407
sewardj207557a2004-08-27 12:00:18 +00004408 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004409 DIP("fimull %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004410 fop = Iop_MulF64;
4411 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004412
sewardj071895f2005-07-29 11:28:38 +00004413 case 2: /* FICOM m32int */
4414 DIP("ficoml %s\n", dis_buf);
4415 /* This forces C1 to zero, which isn't right. */
4416 put_C3210(
4417 binop( Iop_And32,
4418 binop(Iop_Shl32,
4419 binop(Iop_CmpF64,
4420 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00004421 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00004422 loadLE(Ity_I32,mkexpr(addr)))),
4423 mkU8(8)),
4424 mkU32(0x4500)
4425 ));
4426 break;
4427
4428 case 3: /* FICOMP m32int */
4429 DIP("ficompl %s\n", dis_buf);
4430 /* This forces C1 to zero, which isn't right. */
4431 put_C3210(
4432 binop( Iop_And32,
4433 binop(Iop_Shl32,
4434 binop(Iop_CmpF64,
4435 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00004436 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00004437 loadLE(Ity_I32,mkexpr(addr)))),
4438 mkU8(8)),
4439 mkU32(0x4500)
4440 ));
4441 fp_pop();
4442 break;
4443
sewardjce646f22004-08-31 23:55:54 +00004444 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004445 DIP("fisubl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004446 fop = Iop_SubF64;
4447 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004448
sewardj8308aad2004-09-12 11:09:54 +00004449 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004450 DIP("fisubrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004451 fop = Iop_SubF64;
4452 goto do_foprev_m32;
sewardj8308aad2004-09-12 11:09:54 +00004453
sewardjce646f22004-08-31 23:55:54 +00004454 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
sewardj36917e92005-03-21 00:12:15 +00004455 DIP("fidivl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004456 fop = Iop_DivF64;
4457 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004458
sewardjc4eaff32004-09-10 20:25:11 +00004459 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004460 DIP("fidivrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004461 fop = Iop_DivF64;
4462 goto do_foprev_m32;
sewardjc4eaff32004-09-10 20:25:11 +00004463
sewardjce646f22004-08-31 23:55:54 +00004464 do_fop_m32:
sewardj207557a2004-08-27 12:00:18 +00004465 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004466 triop(fop,
4467 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj207557a2004-08-27 12:00:18 +00004468 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00004469 unop(Iop_I32StoF64,
sewardj89cd0932004-09-08 18:23:25 +00004470 loadLE(Ity_I32, mkexpr(addr)))));
sewardjbb53f8c2004-08-14 11:50:01 +00004471 break;
4472
sewardjc4eaff32004-09-10 20:25:11 +00004473 do_foprev_m32:
4474 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004475 triop(fop,
4476 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6c299f32009-12-31 18:00:12 +00004477 unop(Iop_I32StoF64,
sewardjc4eaff32004-09-10 20:25:11 +00004478 loadLE(Ity_I32, mkexpr(addr))),
4479 get_ST(0)));
4480 break;
4481
sewardjbb53f8c2004-08-14 11:50:01 +00004482 default:
4483 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4484 vex_printf("first_opcode == 0xDA\n");
4485 goto decode_fail;
4486 }
sewardj4cb918d2004-12-03 19:43:31 +00004487
sewardjbb53f8c2004-08-14 11:50:01 +00004488 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004489
4490 delta++;
4491 switch (modrm) {
4492
sewardj519d66f2004-12-15 11:57:58 +00004493 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4494 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00004495 DIP("fcmovb %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004496 put_ST_UNCHECKED(0,
4497 IRExpr_Mux0X(
4498 unop(Iop_1Uto8,
4499 mk_x86g_calculate_condition(X86CondB)),
4500 get_ST(0), get_ST(r_src)) );
4501 break;
4502
sewardj3fd5e572004-09-09 22:43:51 +00004503 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4504 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00004505 DIP("fcmovz %%st(%d), %%st(0)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004506 put_ST_UNCHECKED(0,
sewardj3fd5e572004-09-09 22:43:51 +00004507 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004508 unop(Iop_1Uto8,
4509 mk_x86g_calculate_condition(X86CondZ)),
sewardj3fd5e572004-09-09 22:43:51 +00004510 get_ST(0), get_ST(r_src)) );
4511 break;
4512
sewardj519d66f2004-12-15 11:57:58 +00004513 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4514 r_src = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004515 DIP("fcmovbe %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004516 put_ST_UNCHECKED(0,
4517 IRExpr_Mux0X(
4518 unop(Iop_1Uto8,
4519 mk_x86g_calculate_condition(X86CondBE)),
4520 get_ST(0), get_ST(r_src)) );
4521 break;
4522
sewardj8253ad32005-07-04 10:26:32 +00004523 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
4524 r_src = (UInt)modrm - 0xD8;
sewardjd8862cf2006-03-06 19:17:17 +00004525 DIP("fcmovu %%st(%d), %%st(0)\n", (Int)r_src);
sewardj8253ad32005-07-04 10:26:32 +00004526 put_ST_UNCHECKED(0,
4527 IRExpr_Mux0X(
4528 unop(Iop_1Uto8,
4529 mk_x86g_calculate_condition(X86CondP)),
4530 get_ST(0), get_ST(r_src)) );
4531 break;
4532
sewardjbdc7d212004-09-09 02:46:40 +00004533 case 0xE9: /* FUCOMPP %st(0),%st(1) */
4534 DIP("fucompp %%st(0),%%st(1)\n");
sewardjc4be80c2004-09-10 16:17:45 +00004535 /* This forces C1 to zero, which isn't right. */
4536 put_C3210(
4537 binop( Iop_And32,
4538 binop(Iop_Shl32,
4539 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4540 mkU8(8)),
4541 mkU32(0x4500)
4542 ));
sewardjbdc7d212004-09-09 02:46:40 +00004543 fp_pop();
4544 fp_pop();
4545 break;
4546
sewardj5bd4d162004-11-10 13:02:48 +00004547 default:
sewardjbdc7d212004-09-09 02:46:40 +00004548 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004549 }
sewardjbdc7d212004-09-09 02:46:40 +00004550
sewardjbb53f8c2004-08-14 11:50:01 +00004551 }
sewardjd1725d12004-08-12 20:46:53 +00004552 }
4553
4554 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4555 else
4556 if (first_opcode == 0xDB) {
sewardj89cd0932004-09-08 18:23:25 +00004557 if (modrm < 0xC0) {
4558
sewardjfeeb8a82004-11-30 12:30:11 +00004559 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004560 specifies an address. */
4561 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4562 delta += len;
4563
4564 switch (gregOfRM(modrm)) {
4565
4566 case 0: /* FILD m32int */
4567 DIP("fildl %s\n", dis_buf);
4568 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00004569 put_ST(0, unop(Iop_I32StoF64,
sewardj89cd0932004-09-08 18:23:25 +00004570 loadLE(Ity_I32, mkexpr(addr))));
4571 break;
4572
sewardjdd5d2042006-08-03 15:03:19 +00004573 case 1: /* FISTTPL m32 (SSE3) */
4574 DIP("fisttpl %s\n", dis_buf);
4575 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004576 binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjdd5d2042006-08-03 15:03:19 +00004577 fp_pop();
4578 break;
4579
sewardj8f3debf2004-09-08 23:42:23 +00004580 case 2: /* FIST m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004581 DIP("fistl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004582 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004583 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
sewardj8f3debf2004-09-08 23:42:23 +00004584 break;
4585
sewardj89cd0932004-09-08 18:23:25 +00004586 case 3: /* FISTP m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004587 DIP("fistpl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004588 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004589 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
sewardj5bd4d162004-11-10 13:02:48 +00004590 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004591 break;
sewardj17442fe2004-09-20 14:54:28 +00004592
sewardjb3bce0e2004-09-14 23:20:10 +00004593 case 5: { /* FLD extended-real */
sewardj7cb49d72004-10-24 22:31:25 +00004594 /* Uses dirty helper:
sewardj56579232005-03-26 21:49:42 +00004595 ULong x86g_loadF80le ( UInt )
sewardj7cb49d72004-10-24 22:31:25 +00004596 addr holds the address. First, do a dirty call to
sewardjb3bce0e2004-09-14 23:20:10 +00004597 get hold of the data. */
sewardjc5fc7aa2004-10-27 23:00:55 +00004598 IRTemp val = newTemp(Ity_I64);
4599 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4600
sewardj8ea867b2004-10-30 19:03:02 +00004601 IRDirty* d = unsafeIRDirty_1_N (
4602 val,
sewardj2a9ad022004-11-25 02:46:58 +00004603 0/*regparms*/,
sewardj8f40b072005-08-23 19:30:58 +00004604 "x86g_dirtyhelper_loadF80le",
4605 &x86g_dirtyhelper_loadF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004606 args
4607 );
sewardjb3bce0e2004-09-14 23:20:10 +00004608 /* declare that we're reading memory */
4609 d->mFx = Ifx_Read;
sewardj17442fe2004-09-20 14:54:28 +00004610 d->mAddr = mkexpr(addr);
sewardjb3bce0e2004-09-14 23:20:10 +00004611 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004612
4613 /* execute the dirty call, dumping the result in val. */
sewardjb3bce0e2004-09-14 23:20:10 +00004614 stmt( IRStmt_Dirty(d) );
4615 fp_push();
sewardjc5fc7aa2004-10-27 23:00:55 +00004616 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4617
sewardj33dd31b2005-01-08 18:17:32 +00004618 DIP("fldt %s\n", dis_buf);
sewardjb3bce0e2004-09-14 23:20:10 +00004619 break;
4620 }
sewardj17442fe2004-09-20 14:54:28 +00004621
4622 case 7: { /* FSTP extended-real */
sewardj9fc9e782004-11-26 17:57:40 +00004623 /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
sewardjc5fc7aa2004-10-27 23:00:55 +00004624 IRExpr** args
4625 = mkIRExprVec_2( mkexpr(addr),
4626 unop(Iop_ReinterpF64asI64, get_ST(0)) );
4627
sewardj8ea867b2004-10-30 19:03:02 +00004628 IRDirty* d = unsafeIRDirty_0_N (
sewardjf9655262004-10-31 20:02:16 +00004629 0/*regparms*/,
sewardj8f40b072005-08-23 19:30:58 +00004630 "x86g_dirtyhelper_storeF80le",
4631 &x86g_dirtyhelper_storeF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004632 args
4633 );
sewardj17442fe2004-09-20 14:54:28 +00004634 /* declare we're writing memory */
4635 d->mFx = Ifx_Write;
4636 d->mAddr = mkexpr(addr);
4637 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004638
sewardj17442fe2004-09-20 14:54:28 +00004639 /* execute the dirty call. */
4640 stmt( IRStmt_Dirty(d) );
4641 fp_pop();
sewardjc5fc7aa2004-10-27 23:00:55 +00004642
sewardj33dd31b2005-01-08 18:17:32 +00004643 DIP("fstpt\n %s", dis_buf);
sewardj17442fe2004-09-20 14:54:28 +00004644 break;
4645 }
4646
sewardjb3bce0e2004-09-14 23:20:10 +00004647 default:
sewardj89cd0932004-09-08 18:23:25 +00004648 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4649 vex_printf("first_opcode == 0xDB\n");
4650 goto decode_fail;
4651 }
4652
4653 } else {
sewardj8308aad2004-09-12 11:09:54 +00004654
4655 delta++;
4656 switch (modrm) {
4657
sewardj519d66f2004-12-15 11:57:58 +00004658 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
4659 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00004660 DIP("fcmovnb %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004661 put_ST_UNCHECKED(0,
4662 IRExpr_Mux0X(
4663 unop(Iop_1Uto8,
4664 mk_x86g_calculate_condition(X86CondNB)),
4665 get_ST(0), get_ST(r_src)) );
4666 break;
4667
sewardj4e82db72004-10-16 11:32:15 +00004668 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4669 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00004670 DIP("fcmovnz %%st(%d), %%st(0)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004671 put_ST_UNCHECKED(0,
sewardj4e82db72004-10-16 11:32:15 +00004672 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004673 unop(Iop_1Uto8,
4674 mk_x86g_calculate_condition(X86CondNZ)),
sewardj4e82db72004-10-16 11:32:15 +00004675 get_ST(0), get_ST(r_src)) );
4676 break;
4677
sewardj519d66f2004-12-15 11:57:58 +00004678 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
4679 r_src = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004680 DIP("fcmovnbe %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004681 put_ST_UNCHECKED(0,
4682 IRExpr_Mux0X(
4683 unop(Iop_1Uto8,
4684 mk_x86g_calculate_condition(X86CondNBE)),
4685 get_ST(0), get_ST(r_src)) );
4686 break;
4687
sewardj8253ad32005-07-04 10:26:32 +00004688 case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
4689 r_src = (UInt)modrm - 0xD8;
4690 DIP("fcmovnu %%st(%d), %%st(0)\n", (Int)r_src);
4691 put_ST_UNCHECKED(0,
4692 IRExpr_Mux0X(
4693 unop(Iop_1Uto8,
4694 mk_x86g_calculate_condition(X86CondNP)),
4695 get_ST(0), get_ST(r_src)) );
4696 break;
4697
sewardj7df596b2004-12-06 14:29:12 +00004698 case 0xE2:
4699 DIP("fnclex\n");
4700 break;
4701
sewardja0e83b02005-01-06 12:36:38 +00004702 case 0xE3: {
4703 /* Uses dirty helper:
4704 void x86g_do_FINIT ( VexGuestX86State* ) */
4705 IRDirty* d = unsafeIRDirty_0_N (
4706 0/*regparms*/,
4707 "x86g_dirtyhelper_FINIT",
4708 &x86g_dirtyhelper_FINIT,
4709 mkIRExprVec_0()
4710 );
4711 d->needsBBP = True;
4712
4713 /* declare we're writing guest state */
4714 d->nFxState = 5;
4715
4716 d->fxState[0].fx = Ifx_Write;
4717 d->fxState[0].offset = OFFB_FTOP;
4718 d->fxState[0].size = sizeof(UInt);
4719
4720 d->fxState[1].fx = Ifx_Write;
4721 d->fxState[1].offset = OFFB_FPREGS;
4722 d->fxState[1].size = 8 * sizeof(ULong);
4723
4724 d->fxState[2].fx = Ifx_Write;
4725 d->fxState[2].offset = OFFB_FPTAGS;
4726 d->fxState[2].size = 8 * sizeof(UChar);
4727
4728 d->fxState[3].fx = Ifx_Write;
4729 d->fxState[3].offset = OFFB_FPROUND;
4730 d->fxState[3].size = sizeof(UInt);
4731
4732 d->fxState[4].fx = Ifx_Write;
4733 d->fxState[4].offset = OFFB_FC3210;
4734 d->fxState[4].size = sizeof(UInt);
4735
4736 stmt( IRStmt_Dirty(d) );
4737
sewardj33dd31b2005-01-08 18:17:32 +00004738 DIP("fninit\n");
sewardja0e83b02005-01-06 12:36:38 +00004739 break;
4740 }
4741
sewardj8308aad2004-09-12 11:09:54 +00004742 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4743 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4744 break;
4745
sewardj37158712004-10-15 21:23:12 +00004746 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4747 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4748 break;
4749
sewardj8308aad2004-09-12 11:09:54 +00004750 default:
4751 goto decode_fail;
sewardj17442fe2004-09-20 14:54:28 +00004752 }
sewardj89cd0932004-09-08 18:23:25 +00004753 }
sewardjd1725d12004-08-12 20:46:53 +00004754 }
4755
4756 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4757 else
4758 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00004759 if (modrm < 0xC0) {
4760
sewardj89cd0932004-09-08 18:23:25 +00004761 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00004762 specifies an address. */
sewardja58ea662004-08-15 03:12:41 +00004763 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4764 delta += len;
4765
4766 switch (gregOfRM(modrm)) {
4767
4768 case 0: /* FADD double-real */
4769 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4770 break;
4771
sewardjcfded9a2004-09-09 11:44:16 +00004772 case 1: /* FMUL double-real */
4773 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4774 break;
4775
sewardje166ed02004-10-25 02:27:01 +00004776 case 2: /* FCOM double-real */
4777 DIP("fcoml %s\n", dis_buf);
4778 /* This forces C1 to zero, which isn't right. */
4779 put_C3210(
4780 binop( Iop_And32,
4781 binop(Iop_Shl32,
4782 binop(Iop_CmpF64,
4783 get_ST(0),
4784 loadLE(Ity_F64,mkexpr(addr))),
4785 mkU8(8)),
4786 mkU32(0x4500)
4787 ));
4788 break;
4789
sewardj883b00b2004-09-11 09:30:24 +00004790 case 3: /* FCOMP double-real */
sewardje166ed02004-10-25 02:27:01 +00004791 DIP("fcompl %s\n", dis_buf);
sewardj883b00b2004-09-11 09:30:24 +00004792 /* This forces C1 to zero, which isn't right. */
4793 put_C3210(
4794 binop( Iop_And32,
4795 binop(Iop_Shl32,
4796 binop(Iop_CmpF64,
4797 get_ST(0),
4798 loadLE(Ity_F64,mkexpr(addr))),
4799 mkU8(8)),
4800 mkU32(0x4500)
4801 ));
4802 fp_pop();
4803 break;
4804
sewardjcfded9a2004-09-09 11:44:16 +00004805 case 4: /* FSUB double-real */
4806 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4807 break;
4808
sewardj3fd5e572004-09-09 22:43:51 +00004809 case 5: /* FSUBR double-real */
4810 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4811 break;
4812
sewardjcfded9a2004-09-09 11:44:16 +00004813 case 6: /* FDIV double-real */
4814 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4815 break;
4816
sewardj883b00b2004-09-11 09:30:24 +00004817 case 7: /* FDIVR double-real */
4818 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4819 break;
4820
sewardja58ea662004-08-15 03:12:41 +00004821 default:
4822 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4823 vex_printf("first_opcode == 0xDC\n");
4824 goto decode_fail;
4825 }
4826
4827 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004828
4829 delta++;
4830 switch (modrm) {
4831
sewardj3fd5e572004-09-09 22:43:51 +00004832 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4833 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4834 break;
4835
sewardjcfded9a2004-09-09 11:44:16 +00004836 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4837 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4838 break;
4839
sewardj47341042004-09-19 11:55:46 +00004840 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4841 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4842 break;
4843
sewardjcfded9a2004-09-09 11:44:16 +00004844 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4845 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4846 break;
4847
sewardja0d48d62004-09-20 21:19:03 +00004848 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4849 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4850 break;
4851
sewardjbdc7d212004-09-09 02:46:40 +00004852 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4853 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4854 break;
4855
4856 default:
4857 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004858 }
sewardjbdc7d212004-09-09 02:46:40 +00004859
sewardja58ea662004-08-15 03:12:41 +00004860 }
sewardjd1725d12004-08-12 20:46:53 +00004861 }
4862
4863 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
4864 else
4865 if (first_opcode == 0xDD) {
4866
4867 if (modrm < 0xC0) {
4868
sewardjfeeb8a82004-11-30 12:30:11 +00004869 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00004870 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00004871 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4872 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00004873
4874 switch (gregOfRM(modrm)) {
4875
4876 case 0: /* FLD double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004877 DIP("fldl %s\n", dis_buf);
sewardj207557a2004-08-27 12:00:18 +00004878 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00004879 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardjbb53f8c2004-08-14 11:50:01 +00004880 break;
sewardjd1725d12004-08-12 20:46:53 +00004881
sewardjdd5d2042006-08-03 15:03:19 +00004882 case 1: /* FISTTPQ m64 (SSE3) */
4883 DIP("fistppll %s\n", dis_buf);
4884 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004885 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjdd5d2042006-08-03 15:03:19 +00004886 fp_pop();
4887 break;
4888
sewardjd1725d12004-08-12 20:46:53 +00004889 case 2: /* FST double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004890 DIP("fstl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004891 storeLE(mkexpr(addr), get_ST(0));
sewardjd1725d12004-08-12 20:46:53 +00004892 break;
sewardj89cd0932004-09-08 18:23:25 +00004893
sewardja58ea662004-08-15 03:12:41 +00004894 case 3: /* FSTP double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004895 DIP("fstpl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004896 storeLE(mkexpr(addr), get_ST(0));
4897 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004898 break;
sewardjd1725d12004-08-12 20:46:53 +00004899
sewardj9fc9e782004-11-26 17:57:40 +00004900 case 4: { /* FRSTOR m108 */
sewardj893aada2004-11-29 19:57:54 +00004901 /* Uses dirty helper:
4902 VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
4903 IRTemp ew = newTemp(Ity_I32);
4904 IRDirty* d = unsafeIRDirty_0_N (
4905 0/*regparms*/,
4906 "x86g_dirtyhelper_FRSTOR",
4907 &x86g_dirtyhelper_FRSTOR,
4908 mkIRExprVec_1( mkexpr(addr) )
4909 );
sewardj9fc9e782004-11-26 17:57:40 +00004910 d->needsBBP = True;
sewardj893aada2004-11-29 19:57:54 +00004911 d->tmp = ew;
sewardj9fc9e782004-11-26 17:57:40 +00004912 /* declare we're reading memory */
4913 d->mFx = Ifx_Read;
4914 d->mAddr = mkexpr(addr);
4915 d->mSize = 108;
4916
4917 /* declare we're writing guest state */
sewardj893aada2004-11-29 19:57:54 +00004918 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004919
4920 d->fxState[0].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004921 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004922 d->fxState[0].size = sizeof(UInt);
4923
4924 d->fxState[1].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004925 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004926 d->fxState[1].size = 8 * sizeof(ULong);
4927
4928 d->fxState[2].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004929 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004930 d->fxState[2].size = 8 * sizeof(UChar);
4931
4932 d->fxState[3].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004933 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004934 d->fxState[3].size = sizeof(UInt);
4935
4936 d->fxState[4].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004937 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004938 d->fxState[4].size = sizeof(UInt);
4939
4940 stmt( IRStmt_Dirty(d) );
4941
sewardj893aada2004-11-29 19:57:54 +00004942 /* ew contains any emulation warning we may need to
4943 issue. If needed, side-exit to the next insn,
4944 reporting the warning, so that Valgrind's dispatcher
4945 sees the warning. */
4946 put_emwarn( mkexpr(ew) );
4947 stmt(
4948 IRStmt_Exit(
4949 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4950 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004951 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj893aada2004-11-29 19:57:54 +00004952 )
4953 );
4954
sewardj33dd31b2005-01-08 18:17:32 +00004955 DIP("frstor %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00004956 break;
4957 }
4958
4959 case 6: { /* FNSAVE m108 */
sewardj893aada2004-11-29 19:57:54 +00004960 /* Uses dirty helper:
4961 void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
sewardj9fc9e782004-11-26 17:57:40 +00004962 IRDirty* d = unsafeIRDirty_0_N (
4963 0/*regparms*/,
4964 "x86g_dirtyhelper_FSAVE",
4965 &x86g_dirtyhelper_FSAVE,
4966 mkIRExprVec_1( mkexpr(addr) )
4967 );
4968 d->needsBBP = True;
4969 /* declare we're writing memory */
4970 d->mFx = Ifx_Write;
4971 d->mAddr = mkexpr(addr);
4972 d->mSize = 108;
4973
4974 /* declare we're reading guest state */
sewardj893aada2004-11-29 19:57:54 +00004975 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004976
4977 d->fxState[0].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004978 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004979 d->fxState[0].size = sizeof(UInt);
4980
4981 d->fxState[1].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004982 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004983 d->fxState[1].size = 8 * sizeof(ULong);
4984
4985 d->fxState[2].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004986 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004987 d->fxState[2].size = 8 * sizeof(UChar);
4988
4989 d->fxState[3].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004990 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004991 d->fxState[3].size = sizeof(UInt);
4992
4993 d->fxState[4].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004994 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004995 d->fxState[4].size = sizeof(UInt);
4996
4997 stmt( IRStmt_Dirty(d) );
4998
sewardj33dd31b2005-01-08 18:17:32 +00004999 DIP("fnsave %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00005000 break;
5001 }
5002
sewardjd24931d2005-03-20 12:51:39 +00005003 case 7: { /* FNSTSW m16 */
5004 IRExpr* sw = get_FPU_sw();
sewardjdd40fdf2006-12-24 02:20:24 +00005005 vassert(typeOfIRExpr(irsb->tyenv, sw) == Ity_I16);
sewardjd24931d2005-03-20 12:51:39 +00005006 storeLE( mkexpr(addr), sw );
5007 DIP("fnstsw %s\n", dis_buf);
5008 break;
5009 }
5010
sewardjd1725d12004-08-12 20:46:53 +00005011 default:
sewardjbb53f8c2004-08-14 11:50:01 +00005012 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5013 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00005014 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00005015 }
sewardjd1725d12004-08-12 20:46:53 +00005016 } else {
sewardja58ea662004-08-15 03:12:41 +00005017 delta++;
5018 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00005019
sewardj3ddedc42005-03-25 20:30:00 +00005020 case 0xC0 ... 0xC7: /* FFREE %st(?) */
5021 r_dst = (UInt)modrm - 0xC0;
sewardj4a6f3842005-03-26 11:59:23 +00005022 DIP("ffree %%st(%d)\n", (Int)r_dst);
sewardj3ddedc42005-03-25 20:30:00 +00005023 put_ST_TAG ( r_dst, mkU8(0) );
5024 break;
5025
sewardj06c32a02004-09-12 12:07:34 +00005026 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
5027 r_dst = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00005028 DIP("fst %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00005029 /* P4 manual says: "If the destination operand is a
sewardj06c32a02004-09-12 12:07:34 +00005030 non-empty register, the invalid-operation exception
5031 is not generated. Hence put_ST_UNCHECKED. */
5032 put_ST_UNCHECKED(r_dst, get_ST(0));
5033 break;
5034
sewardja58ea662004-08-15 03:12:41 +00005035 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5036 r_dst = (UInt)modrm - 0xD8;
sewardj2d49b432005-02-01 00:37:06 +00005037 DIP("fstp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00005038 /* P4 manual says: "If the destination operand is a
sewardj207557a2004-08-27 12:00:18 +00005039 non-empty register, the invalid-operation exception
5040 is not generated. Hence put_ST_UNCHECKED. */
5041 put_ST_UNCHECKED(r_dst, get_ST(0));
5042 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00005043 break;
sewardjbdc7d212004-09-09 02:46:40 +00005044
5045 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5046 r_dst = (UInt)modrm - 0xE0;
sewardj2d49b432005-02-01 00:37:06 +00005047 DIP("fucom %%st(0),%%st(%d)\n", (Int)r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00005048 /* This forces C1 to zero, which isn't right. */
5049 put_C3210(
5050 binop( Iop_And32,
5051 binop(Iop_Shl32,
5052 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5053 mkU8(8)),
5054 mkU32(0x4500)
5055 ));
sewardjbdc7d212004-09-09 02:46:40 +00005056 break;
5057
5058 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5059 r_dst = (UInt)modrm - 0xE8;
sewardj2d49b432005-02-01 00:37:06 +00005060 DIP("fucomp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00005061 /* This forces C1 to zero, which isn't right. */
5062 put_C3210(
5063 binop( Iop_And32,
5064 binop(Iop_Shl32,
5065 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5066 mkU8(8)),
5067 mkU32(0x4500)
5068 ));
sewardjbdc7d212004-09-09 02:46:40 +00005069 fp_pop();
5070 break;
5071
sewardj5bd4d162004-11-10 13:02:48 +00005072 default:
sewardja58ea662004-08-15 03:12:41 +00005073 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005074 }
sewardjd1725d12004-08-12 20:46:53 +00005075 }
5076 }
5077
5078 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5079 else
5080 if (first_opcode == 0xDE) {
sewardjbdc7d212004-09-09 02:46:40 +00005081
5082 if (modrm < 0xC0) {
sewardjfeeb8a82004-11-30 12:30:11 +00005083
5084 /* bits 5,4,3 are an opcode extension, and the modRM also
5085 specifies an address. */
5086 IROp fop;
5087 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5088 delta += len;
5089
5090 switch (gregOfRM(modrm)) {
5091
5092 case 0: /* FIADD m16int */ /* ST(0) += m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005093 DIP("fiaddw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005094 fop = Iop_AddF64;
5095 goto do_fop_m16;
5096
5097 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005098 DIP("fimulw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005099 fop = Iop_MulF64;
5100 goto do_fop_m16;
5101
sewardj071895f2005-07-29 11:28:38 +00005102 case 2: /* FICOM m16int */
5103 DIP("ficomw %s\n", dis_buf);
5104 /* This forces C1 to zero, which isn't right. */
5105 put_C3210(
5106 binop( Iop_And32,
5107 binop(Iop_Shl32,
5108 binop(Iop_CmpF64,
5109 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005110 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00005111 unop(Iop_16Sto32,
5112 loadLE(Ity_I16,mkexpr(addr))))),
5113 mkU8(8)),
5114 mkU32(0x4500)
5115 ));
5116 break;
5117
5118 case 3: /* FICOMP m16int */
5119 DIP("ficompw %s\n", dis_buf);
5120 /* This forces C1 to zero, which isn't right. */
5121 put_C3210(
5122 binop( Iop_And32,
5123 binop(Iop_Shl32,
5124 binop(Iop_CmpF64,
5125 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005126 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00005127 unop(Iop_16Sto32,
sewardjf1b5b1a2006-02-03 22:54:17 +00005128 loadLE(Ity_I16,mkexpr(addr))))),
sewardj071895f2005-07-29 11:28:38 +00005129 mkU8(8)),
5130 mkU32(0x4500)
5131 ));
5132 fp_pop();
5133 break;
5134
sewardjfeeb8a82004-11-30 12:30:11 +00005135 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005136 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005137 fop = Iop_SubF64;
5138 goto do_fop_m16;
5139
5140 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00005141 DIP("fisubrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005142 fop = Iop_SubF64;
5143 goto do_foprev_m16;
5144
5145 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005146 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005147 fop = Iop_DivF64;
5148 goto do_fop_m16;
5149
5150 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00005151 DIP("fidivrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005152 fop = Iop_DivF64;
5153 goto do_foprev_m16;
5154
5155 do_fop_m16:
5156 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00005157 triop(fop,
5158 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardjfeeb8a82004-11-30 12:30:11 +00005159 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005160 unop(Iop_I32StoF64,
sewardjfeeb8a82004-11-30 12:30:11 +00005161 unop(Iop_16Sto32,
5162 loadLE(Ity_I16, mkexpr(addr))))));
5163 break;
5164
5165 do_foprev_m16:
5166 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00005167 triop(fop,
5168 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6c299f32009-12-31 18:00:12 +00005169 unop(Iop_I32StoF64,
sewardjfeeb8a82004-11-30 12:30:11 +00005170 unop(Iop_16Sto32,
5171 loadLE(Ity_I16, mkexpr(addr)))),
5172 get_ST(0)));
5173 break;
5174
5175 default:
5176 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5177 vex_printf("first_opcode == 0xDE\n");
5178 goto decode_fail;
5179 }
sewardjbdc7d212004-09-09 02:46:40 +00005180
5181 } else {
5182
5183 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00005184 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00005185
sewardjcfded9a2004-09-09 11:44:16 +00005186 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5187 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5188 break;
5189
sewardjbdc7d212004-09-09 02:46:40 +00005190 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5191 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5192 break;
5193
sewardje166ed02004-10-25 02:27:01 +00005194 case 0xD9: /* FCOMPP %st(0),%st(1) */
5195 DIP("fuompp %%st(0),%%st(1)\n");
5196 /* This forces C1 to zero, which isn't right. */
5197 put_C3210(
5198 binop( Iop_And32,
5199 binop(Iop_Shl32,
5200 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5201 mkU8(8)),
5202 mkU32(0x4500)
5203 ));
5204 fp_pop();
5205 fp_pop();
5206 break;
5207
sewardjcfded9a2004-09-09 11:44:16 +00005208 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5209 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
5210 break;
5211
sewardj3fd5e572004-09-09 22:43:51 +00005212 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
5213 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
5214 break;
5215
sewardjbdc7d212004-09-09 02:46:40 +00005216 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5217 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5218 break;
5219
5220 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5221 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5222 break;
5223
5224 default:
5225 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005226 }
sewardjbdc7d212004-09-09 02:46:40 +00005227
5228 }
sewardjd1725d12004-08-12 20:46:53 +00005229 }
5230
5231 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5232 else
5233 if (first_opcode == 0xDF) {
sewardj89cd0932004-09-08 18:23:25 +00005234
5235 if (modrm < 0xC0) {
5236
sewardjfeeb8a82004-11-30 12:30:11 +00005237 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00005238 specifies an address. */
5239 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5240 delta += len;
5241
5242 switch (gregOfRM(modrm)) {
5243
sewardj883b00b2004-09-11 09:30:24 +00005244 case 0: /* FILD m16int */
5245 DIP("fildw %s\n", dis_buf);
5246 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00005247 put_ST(0, unop(Iop_I32StoF64,
sewardj883b00b2004-09-11 09:30:24 +00005248 unop(Iop_16Sto32,
5249 loadLE(Ity_I16, mkexpr(addr)))));
5250 break;
5251
sewardjdd5d2042006-08-03 15:03:19 +00005252 case 1: /* FISTTPS m16 (SSE3) */
5253 DIP("fisttps %s\n", dis_buf);
5254 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005255 binop(Iop_F64toI16S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjdd5d2042006-08-03 15:03:19 +00005256 fp_pop();
5257 break;
5258
sewardj37158712004-10-15 21:23:12 +00005259 case 2: /* FIST m16 */
sewardj33dd31b2005-01-08 18:17:32 +00005260 DIP("fistp %s\n", dis_buf);
sewardj37158712004-10-15 21:23:12 +00005261 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005262 binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
sewardj37158712004-10-15 21:23:12 +00005263 break;
5264
sewardj89cd0932004-09-08 18:23:25 +00005265 case 3: /* FISTP m16 */
sewardj33dd31b2005-01-08 18:17:32 +00005266 DIP("fistps %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00005267 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005268 binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
sewardj8f3debf2004-09-08 23:42:23 +00005269 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00005270 break;
5271
sewardj89cd0932004-09-08 18:23:25 +00005272 case 5: /* FILD m64 */
5273 DIP("fildll %s\n", dis_buf);
5274 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00005275 put_ST(0, binop(Iop_I64StoF64,
sewardj4cb918d2004-12-03 19:43:31 +00005276 get_roundingmode(),
5277 loadLE(Ity_I64, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00005278 break;
sewardj89cd0932004-09-08 18:23:25 +00005279
sewardjcfded9a2004-09-09 11:44:16 +00005280 case 7: /* FISTP m64 */
sewardj33dd31b2005-01-08 18:17:32 +00005281 DIP("fistpll %s\n", dis_buf);
sewardjcfded9a2004-09-09 11:44:16 +00005282 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005283 binop(Iop_F64toI64S, get_roundingmode(), get_ST(0)) );
sewardjcfded9a2004-09-09 11:44:16 +00005284 fp_pop();
5285 break;
5286
sewardj89cd0932004-09-08 18:23:25 +00005287 default:
5288 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5289 vex_printf("first_opcode == 0xDF\n");
5290 goto decode_fail;
5291 }
5292
5293 } else {
sewardjbdc7d212004-09-09 02:46:40 +00005294
5295 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00005296 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00005297
sewardj8fb88692005-07-29 11:57:00 +00005298 case 0xC0: /* FFREEP %st(0) */
5299 DIP("ffreep %%st(%d)\n", 0);
5300 put_ST_TAG ( 0, mkU8(0) );
5301 fp_pop();
5302 break;
5303
sewardjbdc7d212004-09-09 02:46:40 +00005304 case 0xE0: /* FNSTSW %ax */
5305 DIP("fnstsw %%ax\n");
sewardjd24931d2005-03-20 12:51:39 +00005306 /* Get the FPU status word value and dump it in %AX. */
sewardj1d2e77f2008-06-04 09:10:38 +00005307 if (0) {
5308 /* The obvious thing to do is simply dump the 16-bit
5309 status word value in %AX. However, due to a
5310 limitation in Memcheck's origin tracking
5311 machinery, this causes Memcheck not to track the
5312 origin of any undefinedness into %AH (only into
5313 %AL/%AX/%EAX), which means origins are lost in
5314 the sequence "fnstsw %ax; test $M,%ah; jcond .." */
5315 putIReg(2, R_EAX, get_FPU_sw());
5316 } else {
5317 /* So a somewhat lame kludge is to make it very
5318 clear to Memcheck that the value is written to
5319 both %AH and %AL. This generates marginally
5320 worse code, but I don't think it matters much. */
5321 IRTemp t16 = newTemp(Ity_I16);
5322 assign(t16, get_FPU_sw());
5323 putIReg( 1, R_AL, unop(Iop_16to8, mkexpr(t16)) );
5324 putIReg( 1, R_AH, unop(Iop_16HIto8, mkexpr(t16)) );
5325 }
sewardjbdc7d212004-09-09 02:46:40 +00005326 break;
5327
sewardj883b00b2004-09-11 09:30:24 +00005328 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
sewardj8308aad2004-09-12 11:09:54 +00005329 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
sewardj883b00b2004-09-11 09:30:24 +00005330 break;
5331
sewardjfeeb8a82004-11-30 12:30:11 +00005332 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5333 /* not really right since COMIP != UCOMIP */
5334 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5335 break;
5336
sewardjbdc7d212004-09-09 02:46:40 +00005337 default:
5338 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005339 }
sewardj89cd0932004-09-08 18:23:25 +00005340 }
5341
sewardjd1725d12004-08-12 20:46:53 +00005342 }
5343
5344 else
5345 vpanic("dis_FPU(x86): invalid primary opcode");
5346
sewardj69d9d662004-10-14 21:58:52 +00005347 *decode_ok = True;
5348 return delta;
5349
sewardjd1725d12004-08-12 20:46:53 +00005350 decode_fail:
5351 *decode_ok = False;
5352 return delta;
5353}
5354
5355
sewardj464efa42004-11-19 22:17:29 +00005356/*------------------------------------------------------------*/
5357/*--- ---*/
5358/*--- MMX INSTRUCTIONS ---*/
5359/*--- ---*/
5360/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00005361
sewardj464efa42004-11-19 22:17:29 +00005362/* Effect of MMX insns on x87 FPU state (table 11-2 of
5363 IA32 arch manual, volume 3):
5364
5365 Read from, or write to MMX register (viz, any insn except EMMS):
5366 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5367 * FP stack pointer set to zero
5368
5369 EMMS:
5370 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5371 * FP stack pointer set to zero
5372*/
5373
sewardj4cb918d2004-12-03 19:43:31 +00005374static void do_MMX_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00005375{
sewardjdd40fdf2006-12-24 02:20:24 +00005376 Int i;
5377 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5378 IRExpr* zero = mkU32(0);
5379 IRExpr* tag1 = mkU8(1);
sewardj464efa42004-11-19 22:17:29 +00005380 put_ftop(zero);
5381 for (i = 0; i < 8; i++)
5382 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
5383}
5384
sewardj4cb918d2004-12-03 19:43:31 +00005385static void do_EMMS_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00005386{
sewardjdd40fdf2006-12-24 02:20:24 +00005387 Int i;
5388 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5389 IRExpr* zero = mkU32(0);
5390 IRExpr* tag0 = mkU8(0);
sewardj464efa42004-11-19 22:17:29 +00005391 put_ftop(zero);
5392 for (i = 0; i < 8; i++)
5393 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
5394}
5395
5396
5397static IRExpr* getMMXReg ( UInt archreg )
5398{
5399 vassert(archreg < 8);
5400 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5401}
5402
5403
5404static void putMMXReg ( UInt archreg, IRExpr* e )
5405{
5406 vassert(archreg < 8);
sewardjdd40fdf2006-12-24 02:20:24 +00005407 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00005408 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5409}
5410
5411
sewardj38a3f862005-01-13 15:06:51 +00005412/* Helper for non-shift MMX insns. Note this is incomplete in the
5413 sense that it does not first call do_MMX_preamble() -- that is the
5414 responsibility of its caller. */
5415
sewardj464efa42004-11-19 22:17:29 +00005416static
sewardj2d49b432005-02-01 00:37:06 +00005417UInt dis_MMXop_regmem_to_reg ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00005418 Int delta,
sewardj2d49b432005-02-01 00:37:06 +00005419 UChar opc,
5420 HChar* name,
5421 Bool show_granularity )
sewardj464efa42004-11-19 22:17:29 +00005422{
sewardjc9a43662004-11-30 18:51:59 +00005423 HChar dis_buf[50];
sewardj63ba4092004-11-21 12:30:18 +00005424 UChar modrm = getIByte(delta);
5425 Bool isReg = epartIsReg(modrm);
5426 IRExpr* argL = NULL;
5427 IRExpr* argR = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005428 IRExpr* argG = NULL;
5429 IRExpr* argE = NULL;
sewardj63ba4092004-11-21 12:30:18 +00005430 IRTemp res = newTemp(Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00005431
sewardj38a3f862005-01-13 15:06:51 +00005432 Bool invG = False;
5433 IROp op = Iop_INVALID;
5434 void* hAddr = NULL;
sewardj2d49b432005-02-01 00:37:06 +00005435 HChar* hName = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005436 Bool eLeft = False;
5437
sewardj2b7a9202004-11-26 19:15:38 +00005438# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
sewardj464efa42004-11-19 22:17:29 +00005439
sewardj464efa42004-11-19 22:17:29 +00005440 switch (opc) {
sewardjb5452082004-12-04 20:33:02 +00005441 /* Original MMX ones */
sewardj38a3f862005-01-13 15:06:51 +00005442 case 0xFC: op = Iop_Add8x8; break;
5443 case 0xFD: op = Iop_Add16x4; break;
5444 case 0xFE: op = Iop_Add32x2; break;
sewardj464efa42004-11-19 22:17:29 +00005445
sewardj38a3f862005-01-13 15:06:51 +00005446 case 0xEC: op = Iop_QAdd8Sx8; break;
5447 case 0xED: op = Iop_QAdd16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00005448
sewardj38a3f862005-01-13 15:06:51 +00005449 case 0xDC: op = Iop_QAdd8Ux8; break;
5450 case 0xDD: op = Iop_QAdd16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00005451
sewardj38a3f862005-01-13 15:06:51 +00005452 case 0xF8: op = Iop_Sub8x8; break;
5453 case 0xF9: op = Iop_Sub16x4; break;
5454 case 0xFA: op = Iop_Sub32x2; break;
sewardj464efa42004-11-19 22:17:29 +00005455
sewardj38a3f862005-01-13 15:06:51 +00005456 case 0xE8: op = Iop_QSub8Sx8; break;
5457 case 0xE9: op = Iop_QSub16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00005458
sewardj38a3f862005-01-13 15:06:51 +00005459 case 0xD8: op = Iop_QSub8Ux8; break;
5460 case 0xD9: op = Iop_QSub16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00005461
sewardj38a3f862005-01-13 15:06:51 +00005462 case 0xE5: op = Iop_MulHi16Sx4; break;
5463 case 0xD5: op = Iop_Mul16x4; break;
5464 case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
sewardj4340dac2004-11-20 13:17:04 +00005465
sewardj38a3f862005-01-13 15:06:51 +00005466 case 0x74: op = Iop_CmpEQ8x8; break;
5467 case 0x75: op = Iop_CmpEQ16x4; break;
5468 case 0x76: op = Iop_CmpEQ32x2; break;
sewardj4340dac2004-11-20 13:17:04 +00005469
sewardj38a3f862005-01-13 15:06:51 +00005470 case 0x64: op = Iop_CmpGT8Sx8; break;
5471 case 0x65: op = Iop_CmpGT16Sx4; break;
5472 case 0x66: op = Iop_CmpGT32Sx2; break;
sewardj63ba4092004-11-21 12:30:18 +00005473
sewardj5f438dd2011-06-16 11:36:23 +00005474 case 0x6B: op = Iop_QNarrowBin32Sto16Sx4; eLeft = True; break;
5475 case 0x63: op = Iop_QNarrowBin16Sto8Sx8; eLeft = True; break;
5476 case 0x67: op = Iop_QNarrowBin16Sto8Ux8; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005477
sewardj38a3f862005-01-13 15:06:51 +00005478 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
5479 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
5480 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005481
sewardj38a3f862005-01-13 15:06:51 +00005482 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
5483 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
5484 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005485
sewardj38a3f862005-01-13 15:06:51 +00005486 case 0xDB: op = Iop_And64; break;
5487 case 0xDF: op = Iop_And64; invG = True; break;
5488 case 0xEB: op = Iop_Or64; break;
5489 case 0xEF: /* Possibly do better here if argL and argR are the
5490 same reg */
5491 op = Iop_Xor64; break;
sewardj464efa42004-11-19 22:17:29 +00005492
sewardjb5452082004-12-04 20:33:02 +00005493 /* Introduced in SSE1 */
sewardj38a3f862005-01-13 15:06:51 +00005494 case 0xE0: op = Iop_Avg8Ux8; break;
5495 case 0xE3: op = Iop_Avg16Ux4; break;
5496 case 0xEE: op = Iop_Max16Sx4; break;
5497 case 0xDE: op = Iop_Max8Ux8; break;
5498 case 0xEA: op = Iop_Min16Sx4; break;
5499 case 0xDA: op = Iop_Min8Ux8; break;
5500 case 0xE4: op = Iop_MulHi16Ux4; break;
5501 case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
sewardjb5452082004-12-04 20:33:02 +00005502
sewardj164f9272004-12-09 00:39:32 +00005503 /* Introduced in SSE2 */
sewardj38a3f862005-01-13 15:06:51 +00005504 case 0xD4: op = Iop_Add64; break;
5505 case 0xFB: op = Iop_Sub64; break;
sewardj164f9272004-12-09 00:39:32 +00005506
sewardj464efa42004-11-19 22:17:29 +00005507 default:
5508 vex_printf("\n0x%x\n", (Int)opc);
5509 vpanic("dis_MMXop_regmem_to_reg");
5510 }
5511
5512# undef XXX
5513
sewardj38a3f862005-01-13 15:06:51 +00005514 argG = getMMXReg(gregOfRM(modrm));
5515 if (invG)
5516 argG = unop(Iop_Not64, argG);
sewardj63ba4092004-11-21 12:30:18 +00005517
sewardj464efa42004-11-19 22:17:29 +00005518 if (isReg) {
sewardj464efa42004-11-19 22:17:29 +00005519 delta++;
sewardj38a3f862005-01-13 15:06:51 +00005520 argE = getMMXReg(eregOfRM(modrm));
sewardj464efa42004-11-19 22:17:29 +00005521 } else {
5522 Int len;
5523 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5524 delta += len;
sewardj38a3f862005-01-13 15:06:51 +00005525 argE = loadLE(Ity_I64, mkexpr(addr));
sewardj464efa42004-11-19 22:17:29 +00005526 }
5527
sewardj38a3f862005-01-13 15:06:51 +00005528 if (eLeft) {
5529 argL = argE;
5530 argR = argG;
5531 } else {
5532 argL = argG;
5533 argR = argE;
5534 }
5535
5536 if (op != Iop_INVALID) {
5537 vassert(hName == NULL);
5538 vassert(hAddr == NULL);
5539 assign(res, binop(op, argL, argR));
5540 } else {
5541 vassert(hName != NULL);
5542 vassert(hAddr != NULL);
5543 assign( res,
5544 mkIRExprCCall(
5545 Ity_I64,
5546 0/*regparms*/, hName, hAddr,
5547 mkIRExprVec_2( argL, argR )
5548 )
5549 );
sewardj63ba4092004-11-21 12:30:18 +00005550 }
5551
5552 putMMXReg( gregOfRM(modrm), mkexpr(res) );
5553
sewardj464efa42004-11-19 22:17:29 +00005554 DIP("%s%s %s, %s\n",
sewardj2d49b432005-02-01 00:37:06 +00005555 name, show_granularity ? nameMMXGran(opc & 3) : "",
sewardj464efa42004-11-19 22:17:29 +00005556 ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5557 nameMMXReg(gregOfRM(modrm)) );
5558
5559 return delta;
5560}
5561
5562
sewardj38a3f862005-01-13 15:06:51 +00005563/* Vector by scalar shift of G by the amount specified at the bottom
5564 of E. This is a straight copy of dis_SSE_shiftG_byE. */
5565
sewardj52d04912005-07-03 00:52:48 +00005566static UInt dis_MMX_shiftG_byE ( UChar sorb, Int delta,
sewardj38a3f862005-01-13 15:06:51 +00005567 HChar* opname, IROp op )
5568{
5569 HChar dis_buf[50];
5570 Int alen, size;
5571 IRTemp addr;
5572 Bool shl, shr, sar;
5573 UChar rm = getIByte(delta);
5574 IRTemp g0 = newTemp(Ity_I64);
5575 IRTemp g1 = newTemp(Ity_I64);
5576 IRTemp amt = newTemp(Ity_I32);
5577 IRTemp amt8 = newTemp(Ity_I8);
5578
5579 if (epartIsReg(rm)) {
5580 assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
5581 DIP("%s %s,%s\n", opname,
5582 nameMMXReg(eregOfRM(rm)),
5583 nameMMXReg(gregOfRM(rm)) );
5584 delta++;
5585 } else {
5586 addr = disAMode ( &alen, sorb, delta, dis_buf );
5587 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
5588 DIP("%s %s,%s\n", opname,
5589 dis_buf,
5590 nameMMXReg(gregOfRM(rm)) );
5591 delta += alen;
5592 }
5593 assign( g0, getMMXReg(gregOfRM(rm)) );
5594 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
5595
5596 shl = shr = sar = False;
5597 size = 0;
5598 switch (op) {
5599 case Iop_ShlN16x4: shl = True; size = 32; break;
5600 case Iop_ShlN32x2: shl = True; size = 32; break;
5601 case Iop_Shl64: shl = True; size = 64; break;
5602 case Iop_ShrN16x4: shr = True; size = 16; break;
5603 case Iop_ShrN32x2: shr = True; size = 32; break;
5604 case Iop_Shr64: shr = True; size = 64; break;
5605 case Iop_SarN16x4: sar = True; size = 16; break;
5606 case Iop_SarN32x2: sar = True; size = 32; break;
5607 default: vassert(0);
5608 }
5609
5610 if (shl || shr) {
5611 assign(
5612 g1,
5613 IRExpr_Mux0X(
5614 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5615 mkU64(0),
5616 binop(op, mkexpr(g0), mkexpr(amt8))
5617 )
5618 );
5619 } else
5620 if (sar) {
5621 assign(
5622 g1,
5623 IRExpr_Mux0X(
5624 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5625 binop(op, mkexpr(g0), mkU8(size-1)),
5626 binop(op, mkexpr(g0), mkexpr(amt8))
5627 )
5628 );
5629 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005630 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005631 vassert(0);
5632 }
5633
5634 putMMXReg( gregOfRM(rm), mkexpr(g1) );
5635 return delta;
5636}
5637
5638
5639/* Vector by scalar shift of E by an immediate byte. This is a
5640 straight copy of dis_SSE_shiftE_imm. */
5641
5642static
sewardj52d04912005-07-03 00:52:48 +00005643UInt dis_MMX_shiftE_imm ( Int delta, HChar* opname, IROp op )
sewardj38a3f862005-01-13 15:06:51 +00005644{
5645 Bool shl, shr, sar;
5646 UChar rm = getIByte(delta);
5647 IRTemp e0 = newTemp(Ity_I64);
5648 IRTemp e1 = newTemp(Ity_I64);
5649 UChar amt, size;
5650 vassert(epartIsReg(rm));
5651 vassert(gregOfRM(rm) == 2
5652 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00005653 amt = getIByte(delta+1);
sewardj38a3f862005-01-13 15:06:51 +00005654 delta += 2;
5655 DIP("%s $%d,%s\n", opname,
5656 (Int)amt,
5657 nameMMXReg(eregOfRM(rm)) );
5658
5659 assign( e0, getMMXReg(eregOfRM(rm)) );
5660
5661 shl = shr = sar = False;
5662 size = 0;
5663 switch (op) {
5664 case Iop_ShlN16x4: shl = True; size = 16; break;
5665 case Iop_ShlN32x2: shl = True; size = 32; break;
5666 case Iop_Shl64: shl = True; size = 64; break;
5667 case Iop_SarN16x4: sar = True; size = 16; break;
5668 case Iop_SarN32x2: sar = True; size = 32; break;
5669 case Iop_ShrN16x4: shr = True; size = 16; break;
5670 case Iop_ShrN32x2: shr = True; size = 32; break;
5671 case Iop_Shr64: shr = True; size = 64; break;
5672 default: vassert(0);
5673 }
5674
5675 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00005676 assign( e1, amt >= size
5677 ? mkU64(0)
5678 : binop(op, mkexpr(e0), mkU8(amt))
5679 );
sewardj38a3f862005-01-13 15:06:51 +00005680 } else
5681 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00005682 assign( e1, amt >= size
5683 ? binop(op, mkexpr(e0), mkU8(size-1))
5684 : binop(op, mkexpr(e0), mkU8(amt))
5685 );
sewardj38a3f862005-01-13 15:06:51 +00005686 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005687 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005688 vassert(0);
5689 }
5690
5691 putMMXReg( eregOfRM(rm), mkexpr(e1) );
5692 return delta;
5693}
5694
5695
5696/* Completely handle all MMX instructions except emms. */
sewardj464efa42004-11-19 22:17:29 +00005697
5698static
sewardj52d04912005-07-03 00:52:48 +00005699UInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, Int delta )
sewardj464efa42004-11-19 22:17:29 +00005700{
5701 Int len;
5702 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005703 HChar dis_buf[50];
sewardj464efa42004-11-19 22:17:29 +00005704 UChar opc = getIByte(delta);
5705 delta++;
5706
sewardj4cb918d2004-12-03 19:43:31 +00005707 /* dis_MMX handles all insns except emms. */
5708 do_MMX_preamble();
sewardj464efa42004-11-19 22:17:29 +00005709
5710 switch (opc) {
5711
sewardj2b7a9202004-11-26 19:15:38 +00005712 case 0x6E:
5713 /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
sewardj9df271d2004-12-31 22:37:42 +00005714 if (sz != 4)
5715 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005716 modrm = getIByte(delta);
5717 if (epartIsReg(modrm)) {
5718 delta++;
5719 putMMXReg(
5720 gregOfRM(modrm),
5721 binop( Iop_32HLto64,
5722 mkU32(0),
5723 getIReg(4, eregOfRM(modrm)) ) );
5724 DIP("movd %s, %s\n",
5725 nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5726 } else {
5727 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5728 delta += len;
5729 putMMXReg(
5730 gregOfRM(modrm),
5731 binop( Iop_32HLto64,
5732 mkU32(0),
5733 loadLE(Ity_I32, mkexpr(addr)) ) );
5734 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
5735 }
5736 break;
5737
5738 case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
sewardj9df271d2004-12-31 22:37:42 +00005739 if (sz != 4)
5740 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005741 modrm = getIByte(delta);
5742 if (epartIsReg(modrm)) {
5743 delta++;
5744 putIReg( 4, eregOfRM(modrm),
5745 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5746 DIP("movd %s, %s\n",
5747 nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
5748 } else {
5749 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5750 delta += len;
5751 storeLE( mkexpr(addr),
5752 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5753 DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
5754 }
5755 break;
5756
sewardj464efa42004-11-19 22:17:29 +00005757 case 0x6F:
5758 /* MOVQ (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 modrm = getIByte(delta);
5762 if (epartIsReg(modrm)) {
5763 delta++;
5764 putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5765 DIP("movq %s, %s\n",
5766 nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5767 } else {
5768 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5769 delta += len;
5770 putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5771 DIP("movq %s, %s\n",
5772 dis_buf, nameMMXReg(gregOfRM(modrm)));
5773 }
5774 break;
5775
5776 case 0x7F:
5777 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj9df271d2004-12-31 22:37:42 +00005778 if (sz != 4)
5779 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005780 modrm = getIByte(delta);
5781 if (epartIsReg(modrm)) {
sewardj9ca26402005-10-03 02:44:01 +00005782 delta++;
5783 putMMXReg( eregOfRM(modrm), getMMXReg(gregOfRM(modrm)) );
5784 DIP("movq %s, %s\n",
5785 nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
sewardj464efa42004-11-19 22:17:29 +00005786 } else {
5787 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5788 delta += len;
sewardj893aada2004-11-29 19:57:54 +00005789 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
sewardj464efa42004-11-19 22:17:29 +00005790 DIP("mov(nt)q %s, %s\n",
5791 nameMMXReg(gregOfRM(modrm)), dis_buf);
5792 }
5793 break;
5794
sewardj4340dac2004-11-20 13:17:04 +00005795 case 0xFC:
5796 case 0xFD:
5797 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005798 if (sz != 4)
5799 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005800 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5801 break;
5802
sewardj4340dac2004-11-20 13:17:04 +00005803 case 0xEC:
5804 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005805 if (sz != 4)
5806 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005807 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5808 break;
5809
sewardj4340dac2004-11-20 13:17:04 +00005810 case 0xDC:
5811 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005812 if (sz != 4)
5813 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005814 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5815 break;
5816
sewardj4340dac2004-11-20 13:17:04 +00005817 case 0xF8:
5818 case 0xF9:
5819 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005820 if (sz != 4)
5821 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005822 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
5823 break;
5824
sewardj4340dac2004-11-20 13:17:04 +00005825 case 0xE8:
5826 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005827 if (sz != 4)
5828 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005829 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5830 break;
5831
sewardj4340dac2004-11-20 13:17:04 +00005832 case 0xD8:
5833 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005834 if (sz != 4)
5835 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005836 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5837 break;
5838
5839 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005840 if (sz != 4)
5841 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005842 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5843 break;
5844
5845 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005846 if (sz != 4)
5847 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005848 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5849 break;
5850
sewardj4340dac2004-11-20 13:17:04 +00005851 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
5852 vassert(sz == 4);
5853 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
5854 break;
5855
5856 case 0x74:
5857 case 0x75:
5858 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005859 if (sz != 4)
5860 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00005861 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
5862 break;
5863
5864 case 0x64:
5865 case 0x65:
5866 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005867 if (sz != 4)
5868 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00005869 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
5870 break;
5871
sewardj63ba4092004-11-21 12:30:18 +00005872 case 0x6B: /* PACKSSDW (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, "packssdw", False );
5876 break;
5877
5878 case 0x63: /* PACKSSWB (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, "packsswb", False );
5882 break;
5883
5884 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005885 if (sz != 4)
5886 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005887 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
5888 break;
5889
5890 case 0x68:
5891 case 0x69:
5892 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005893 if (sz != 4)
5894 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005895 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
5896 break;
5897
5898 case 0x60:
5899 case 0x61:
5900 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005901 if (sz != 4)
5902 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005903 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
5904 break;
5905
5906 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005907 if (sz != 4)
5908 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005909 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
5910 break;
5911
5912 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005913 if (sz != 4)
5914 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005915 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
5916 break;
5917
5918 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005919 if (sz != 4)
5920 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005921 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
5922 break;
5923
5924 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005925 if (sz != 4)
5926 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005927 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
sewardj38a3f862005-01-13 15:06:51 +00005928 break;
sewardj63ba4092004-11-21 12:30:18 +00005929
sewardj38a3f862005-01-13 15:06:51 +00005930# define SHIFT_BY_REG(_name,_op) \
5931 delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
5932 break;
sewardj8d14a592004-11-21 17:04:50 +00005933
sewardj38a3f862005-01-13 15:06:51 +00005934 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
5935 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
5936 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
5937 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
sewardj8d14a592004-11-21 17:04:50 +00005938
sewardj38a3f862005-01-13 15:06:51 +00005939 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
5940 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
5941 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
5942 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
5943
5944 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
5945 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
5946 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
5947
5948# undef SHIFT_BY_REG
sewardj8d14a592004-11-21 17:04:50 +00005949
sewardj2b7a9202004-11-26 19:15:38 +00005950 case 0x71:
5951 case 0x72:
5952 case 0x73: {
5953 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardja8415ff2005-01-21 20:55:36 +00005954 UChar byte2, subopc;
sewardj38a3f862005-01-13 15:06:51 +00005955 if (sz != 4)
5956 goto mmx_decode_failure;
sewardj38a3f862005-01-13 15:06:51 +00005957 byte2 = getIByte(delta); /* amode / sub-opcode */
sewardj9b45b482005-02-07 01:42:18 +00005958 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj2b7a9202004-11-26 19:15:38 +00005959
sewardj38a3f862005-01-13 15:06:51 +00005960# define SHIFT_BY_IMM(_name,_op) \
5961 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
5962 } while (0)
sewardj2b7a9202004-11-26 19:15:38 +00005963
sewardj2b7a9202004-11-26 19:15:38 +00005964 if (subopc == 2 /*SRL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005965 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005966 else if (subopc == 2 /*SRL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005967 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005968 else if (subopc == 2 /*SRL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00005969 SHIFT_BY_IMM("psrlq", Iop_Shr64);
sewardj2b7a9202004-11-26 19:15:38 +00005970
5971 else if (subopc == 4 /*SAR*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005972 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005973 else if (subopc == 4 /*SAR*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005974 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005975
5976 else if (subopc == 6 /*SHL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005977 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005978 else if (subopc == 6 /*SHL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005979 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005980 else if (subopc == 6 /*SHL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00005981 SHIFT_BY_IMM("psllq", Iop_Shl64);
sewardj2b7a9202004-11-26 19:15:38 +00005982
5983 else goto mmx_decode_failure;
5984
sewardj38a3f862005-01-13 15:06:51 +00005985# undef SHIFT_BY_IMM
sewardj2b7a9202004-11-26 19:15:38 +00005986 break;
5987 }
5988
sewardjd71ba832006-12-27 01:15:29 +00005989 case 0xF7: {
5990 IRTemp addr = newTemp(Ity_I32);
5991 IRTemp regD = newTemp(Ity_I64);
5992 IRTemp regM = newTemp(Ity_I64);
5993 IRTemp mask = newTemp(Ity_I64);
5994 IRTemp olddata = newTemp(Ity_I64);
5995 IRTemp newdata = newTemp(Ity_I64);
5996
5997 modrm = getIByte(delta);
5998 if (sz != 4 || (!epartIsReg(modrm)))
5999 goto mmx_decode_failure;
6000 delta++;
6001
6002 assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
6003 assign( regM, getMMXReg( eregOfRM(modrm) ));
6004 assign( regD, getMMXReg( gregOfRM(modrm) ));
6005 assign( mask, binop(Iop_SarN8x8, mkexpr(regM), mkU8(7)) );
6006 assign( olddata, loadLE( Ity_I64, mkexpr(addr) ));
6007 assign( newdata,
6008 binop(Iop_Or64,
6009 binop(Iop_And64,
6010 mkexpr(regD),
6011 mkexpr(mask) ),
6012 binop(Iop_And64,
6013 mkexpr(olddata),
6014 unop(Iop_Not64, mkexpr(mask)))) );
6015 storeLE( mkexpr(addr), mkexpr(newdata) );
6016 DIP("maskmovq %s,%s\n", nameMMXReg( eregOfRM(modrm) ),
6017 nameMMXReg( gregOfRM(modrm) ) );
6018 break;
6019 }
6020
sewardj2b7a9202004-11-26 19:15:38 +00006021 /* --- MMX decode failure --- */
sewardj464efa42004-11-19 22:17:29 +00006022 default:
sewardj2b7a9202004-11-26 19:15:38 +00006023 mmx_decode_failure:
sewardj464efa42004-11-19 22:17:29 +00006024 *decode_ok = False;
6025 return delta; /* ignored */
6026
6027 }
6028
6029 *decode_ok = True;
6030 return delta;
6031}
6032
6033
6034/*------------------------------------------------------------*/
6035/*--- More misc arithmetic and other obscure insns. ---*/
6036/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00006037
6038/* Double length left and right shifts. Apparently only required in
6039 v-size (no b- variant). */
6040static
6041UInt dis_SHLRD_Gv_Ev ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00006042 Int delta, UChar modrm,
sewardja06e5562004-07-14 13:18:05 +00006043 Int sz,
6044 IRExpr* shift_amt,
6045 Bool amt_is_literal,
sewardj2d49b432005-02-01 00:37:06 +00006046 HChar* shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00006047 Bool left_shift )
6048{
6049 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
6050 for printing it. And eip on entry points at the modrm byte. */
6051 Int len;
sewardjc9a43662004-11-30 18:51:59 +00006052 HChar dis_buf[50];
sewardja06e5562004-07-14 13:18:05 +00006053
sewardj6d2638e2004-07-15 09:38:27 +00006054 IRType ty = szToITy(sz);
6055 IRTemp gsrc = newTemp(ty);
6056 IRTemp esrc = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00006057 IRTemp addr = IRTemp_INVALID;
sewardj6d2638e2004-07-15 09:38:27 +00006058 IRTemp tmpSH = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00006059 IRTemp tmpL = IRTemp_INVALID;
6060 IRTemp tmpRes = IRTemp_INVALID;
6061 IRTemp tmpSubSh = IRTemp_INVALID;
sewardja06e5562004-07-14 13:18:05 +00006062 IROp mkpair;
6063 IROp getres;
6064 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00006065 IRExpr* mask = NULL;
6066
6067 vassert(sz == 2 || sz == 4);
6068
6069 /* The E-part is the destination; this is shifted. The G-part
6070 supplies bits to be shifted into the E-part, but is not
6071 changed.
6072
6073 If shifting left, form a double-length word with E at the top
6074 and G at the bottom, and shift this left. The result is then in
6075 the high part.
6076
6077 If shifting right, form a double-length word with G at the top
6078 and E at the bottom, and shift this right. The result is then
6079 at the bottom. */
6080
6081 /* Fetch the operands. */
6082
6083 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
6084
6085 if (epartIsReg(modrm)) {
6086 delta++;
6087 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00006088 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00006089 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00006090 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00006091 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
6092 } else {
6093 addr = disAMode ( &len, sorb, delta, dis_buf );
6094 delta += len;
6095 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00006096 DIP("sh%cd%c %s, %s, %s\n",
6097 ( left_shift ? 'l' : 'r' ), nameISize(sz),
6098 shift_amt_txt,
6099 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00006100 }
6101
6102 /* Round up the relevant primops. */
6103
6104 if (sz == 4) {
6105 tmpL = newTemp(Ity_I64);
6106 tmpRes = newTemp(Ity_I32);
6107 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00006108 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00006109 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00006110 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
6111 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00006112 } else {
6113 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00006114 tmpL = newTemp(Ity_I32);
6115 tmpRes = newTemp(Ity_I16);
6116 tmpSubSh = newTemp(Ity_I16);
6117 mkpair = Iop_16HLto32;
6118 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
6119 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
6120 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00006121 }
6122
6123 /* Do the shift, calculate the subshift value, and set
6124 the flag thunk. */
6125
sewardj8c7f1ab2004-07-29 20:31:09 +00006126 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
6127
sewardja06e5562004-07-14 13:18:05 +00006128 if (left_shift)
6129 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
6130 else
6131 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
6132
6133 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
6134 assign( tmpSubSh,
6135 unop(getres,
6136 binop(shift,
6137 mkexpr(tmpL),
6138 binop(Iop_And8,
6139 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6140 mask))) );
sewardja06e5562004-07-14 13:18:05 +00006141
sewardj2a2ba8b2004-11-08 13:14:06 +00006142 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
6143 tmpRes, tmpSubSh, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00006144
6145 /* Put result back. */
6146
6147 if (epartIsReg(modrm)) {
6148 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
6149 } else {
6150 storeLE( mkexpr(addr), mkexpr(tmpRes) );
6151 }
6152
6153 if (amt_is_literal) delta++;
6154 return delta;
6155}
6156
6157
sewardj1c6f9912004-09-07 10:15:24 +00006158/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
6159 required. */
6160
6161typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
6162
sewardj2d49b432005-02-01 00:37:06 +00006163static HChar* nameBtOp ( BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00006164{
6165 switch (op) {
6166 case BtOpNone: return "";
6167 case BtOpSet: return "s";
6168 case BtOpReset: return "r";
6169 case BtOpComp: return "c";
6170 default: vpanic("nameBtOp(x86)");
6171 }
6172}
6173
6174
6175static
sewardj02834302010-07-29 18:10:51 +00006176UInt dis_bt_G_E ( VexAbiInfo* vbi,
6177 UChar sorb, Bool locked, Int sz, Int delta, BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00006178{
sewardjc9a43662004-11-30 18:51:59 +00006179 HChar dis_buf[50];
sewardj1c6f9912004-09-07 10:15:24 +00006180 UChar modrm;
6181 Int len;
6182 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
sewardje9d8a262009-07-01 08:06:34 +00006183 t_addr1, t_esp, t_mask, t_new;
sewardj1c6f9912004-09-07 10:15:24 +00006184
6185 vassert(sz == 2 || sz == 4);
6186
6187 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
sewardje9d8a262009-07-01 08:06:34 +00006188 = t_addr0 = t_addr1 = t_esp
6189 = t_mask = t_new = IRTemp_INVALID;
sewardj1c6f9912004-09-07 10:15:24 +00006190
6191 t_fetched = newTemp(Ity_I8);
sewardje9d8a262009-07-01 08:06:34 +00006192 t_new = newTemp(Ity_I8);
sewardj1c6f9912004-09-07 10:15:24 +00006193 t_bitno0 = newTemp(Ity_I32);
6194 t_bitno1 = newTemp(Ity_I32);
6195 t_bitno2 = newTemp(Ity_I8);
6196 t_addr1 = newTemp(Ity_I32);
6197 modrm = getIByte(delta);
6198
sewardj9ed16802005-08-24 10:46:19 +00006199 assign( t_bitno0, widenSto32(getIReg(sz, gregOfRM(modrm))) );
sewardj1c6f9912004-09-07 10:15:24 +00006200
6201 if (epartIsReg(modrm)) {
sewardj1c6f9912004-09-07 10:15:24 +00006202 delta++;
6203 /* Get it onto the client's stack. */
6204 t_esp = newTemp(Ity_I32);
6205 t_addr0 = newTemp(Ity_I32);
6206
sewardj02834302010-07-29 18:10:51 +00006207 /* For the choice of the value 128, see comment in dis_bt_G_E in
6208 guest_amd64_toIR.c. We point out here only that 128 is
6209 fast-cased in Memcheck and is > 0, so seems like a good
6210 choice. */
6211 vassert(vbi->guest_stack_redzone_size == 0);
6212 assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(128)) );
sewardj1c6f9912004-09-07 10:15:24 +00006213 putIReg(4, R_ESP, mkexpr(t_esp));
6214
6215 storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
6216
6217 /* Make t_addr0 point at it. */
6218 assign( t_addr0, mkexpr(t_esp) );
6219
6220 /* Mask out upper bits of the shift amount, since we're doing a
6221 reg. */
6222 assign( t_bitno1, binop(Iop_And32,
6223 mkexpr(t_bitno0),
6224 mkU32(sz == 4 ? 31 : 15)) );
6225
6226 } else {
6227 t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
6228 delta += len;
6229 assign( t_bitno1, mkexpr(t_bitno0) );
6230 }
6231
6232 /* At this point: t_addr0 is the address being operated on. If it
6233 was a reg, we will have pushed it onto the client's stack.
6234 t_bitno1 is the bit number, suitably masked in the case of a
6235 reg. */
6236
6237 /* Now the main sequence. */
6238 assign( t_addr1,
6239 binop(Iop_Add32,
6240 mkexpr(t_addr0),
6241 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
6242
6243 /* t_addr1 now holds effective address */
6244
6245 assign( t_bitno2,
6246 unop(Iop_32to8,
6247 binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
6248
6249 /* t_bitno2 contains offset of bit within byte */
6250
6251 if (op != BtOpNone) {
6252 t_mask = newTemp(Ity_I8);
6253 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
6254 }
sewardj4963a422004-10-14 23:34:03 +00006255
sewardj1c6f9912004-09-07 10:15:24 +00006256 /* t_mask is now a suitable byte mask */
6257
6258 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
6259
6260 if (op != BtOpNone) {
6261 switch (op) {
sewardje9d8a262009-07-01 08:06:34 +00006262 case BtOpSet:
6263 assign( t_new,
6264 binop(Iop_Or8, mkexpr(t_fetched), mkexpr(t_mask)) );
sewardj1c6f9912004-09-07 10:15:24 +00006265 break;
sewardje9d8a262009-07-01 08:06:34 +00006266 case BtOpComp:
6267 assign( t_new,
6268 binop(Iop_Xor8, mkexpr(t_fetched), mkexpr(t_mask)) );
sewardj1c6f9912004-09-07 10:15:24 +00006269 break;
sewardje9d8a262009-07-01 08:06:34 +00006270 case BtOpReset:
6271 assign( t_new,
6272 binop(Iop_And8, mkexpr(t_fetched),
6273 unop(Iop_Not8, mkexpr(t_mask))) );
sewardj1c6f9912004-09-07 10:15:24 +00006274 break;
6275 default:
6276 vpanic("dis_bt_G_E(x86)");
6277 }
sewardje9d8a262009-07-01 08:06:34 +00006278 if (locked && !epartIsReg(modrm)) {
6279 casLE( mkexpr(t_addr1), mkexpr(t_fetched)/*expd*/,
6280 mkexpr(t_new)/*new*/,
6281 guest_EIP_curr_instr );
6282 } else {
6283 storeLE( mkexpr(t_addr1), mkexpr(t_new) );
6284 }
sewardj1c6f9912004-09-07 10:15:24 +00006285 }
6286
6287 /* Side effect done; now get selected bit into Carry flag */
sewardj2a2ba8b2004-11-08 13:14:06 +00006288 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00006289 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006290 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00006291 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00006292 OFFB_CC_DEP1,
sewardj1c6f9912004-09-07 10:15:24 +00006293 binop(Iop_And32,
6294 binop(Iop_Shr32,
6295 unop(Iop_8Uto32, mkexpr(t_fetched)),
sewardj5bd4d162004-11-10 13:02:48 +00006296 mkexpr(t_bitno2)),
6297 mkU32(1)))
sewardj1c6f9912004-09-07 10:15:24 +00006298 );
sewardja3b7e3a2005-04-05 01:54:19 +00006299 /* Set NDEP even though it isn't used. This makes redundant-PUT
6300 elimination of previous stores to this field work better. */
6301 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00006302
6303 /* Move reg operand from stack back to reg */
6304 if (epartIsReg(modrm)) {
6305 /* t_esp still points at it. */
sewardj4963a422004-10-14 23:34:03 +00006306 putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
sewardj02834302010-07-29 18:10:51 +00006307 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(128)) );
sewardj1c6f9912004-09-07 10:15:24 +00006308 }
6309
6310 DIP("bt%s%c %s, %s\n",
6311 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
6312 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
6313
6314 return delta;
6315}
sewardjce646f22004-08-31 23:55:54 +00006316
6317
6318
6319/* Handle BSF/BSR. Only v-size seems necessary. */
6320static
sewardj52d04912005-07-03 00:52:48 +00006321UInt dis_bs_E_G ( UChar sorb, Int sz, Int delta, Bool fwds )
sewardjce646f22004-08-31 23:55:54 +00006322{
6323 Bool isReg;
6324 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00006325 HChar dis_buf[50];
sewardjce646f22004-08-31 23:55:54 +00006326
6327 IRType ty = szToITy(sz);
6328 IRTemp src = newTemp(ty);
6329 IRTemp dst = newTemp(ty);
6330
6331 IRTemp src32 = newTemp(Ity_I32);
6332 IRTemp dst32 = newTemp(Ity_I32);
6333 IRTemp src8 = newTemp(Ity_I8);
6334
6335 vassert(sz == 4 || sz == 2);
sewardjce646f22004-08-31 23:55:54 +00006336
6337 modrm = getIByte(delta);
6338
6339 isReg = epartIsReg(modrm);
6340 if (isReg) {
6341 delta++;
6342 assign( src, getIReg(sz, eregOfRM(modrm)) );
6343 } else {
6344 Int len;
6345 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6346 delta += len;
6347 assign( src, loadLE(ty, mkexpr(addr)) );
6348 }
6349
6350 DIP("bs%c%c %s, %s\n",
6351 fwds ? 'f' : 'r', nameISize(sz),
6352 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
6353 nameIReg(sz, gregOfRM(modrm)));
6354
6355 /* Generate an 8-bit expression which is zero iff the
6356 original is zero, and nonzero otherwise */
6357 assign( src8,
6358 unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
6359 mkexpr(src), mkU(ty,0))) );
6360
6361 /* Flags: Z is 1 iff source value is zero. All others
6362 are undefined -- we force them to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00006363 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006364 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00006365 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00006366 OFFB_CC_DEP1,
sewardjce646f22004-08-31 23:55:54 +00006367 IRExpr_Mux0X( mkexpr(src8),
6368 /* src==0 */
sewardj2a9ad022004-11-25 02:46:58 +00006369 mkU32(X86G_CC_MASK_Z),
sewardjce646f22004-08-31 23:55:54 +00006370 /* src!=0 */
6371 mkU32(0)
6372 )
6373 ));
sewardja3b7e3a2005-04-05 01:54:19 +00006374 /* Set NDEP even though it isn't used. This makes redundant-PUT
6375 elimination of previous stores to this field work better. */
6376 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00006377
6378 /* Result: iff source value is zero, we can't use
6379 Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
6380 But anyway, Intel x86 semantics say the result is undefined in
6381 such situations. Hence handle the zero case specially. */
6382
6383 /* Bleh. What we compute:
6384
6385 bsf32: if src == 0 then 0 else Ctz32(src)
6386 bsr32: if src == 0 then 0 else 31 - Clz32(src)
6387
6388 bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
6389 bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
6390
6391 First, widen src to 32 bits if it is not already.
sewardj37158712004-10-15 21:23:12 +00006392
6393 Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
6394 dst register unchanged when src == 0. Hence change accordingly.
sewardjce646f22004-08-31 23:55:54 +00006395 */
6396 if (sz == 2)
6397 assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
6398 else
6399 assign( src32, mkexpr(src) );
6400
6401 /* The main computation, guarding against zero. */
6402 assign( dst32,
6403 IRExpr_Mux0X(
6404 mkexpr(src8),
sewardj37158712004-10-15 21:23:12 +00006405 /* src == 0 -- leave dst unchanged */
6406 widenUto32( getIReg( sz, gregOfRM(modrm) ) ),
sewardjce646f22004-08-31 23:55:54 +00006407 /* src != 0 */
6408 fwds ? unop(Iop_Ctz32, mkexpr(src32))
6409 : binop(Iop_Sub32,
6410 mkU32(31),
6411 unop(Iop_Clz32, mkexpr(src32)))
6412 )
6413 );
6414
6415 if (sz == 2)
6416 assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
6417 else
6418 assign( dst, mkexpr(dst32) );
6419
6420 /* dump result back */
6421 putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
6422
6423 return delta;
6424}
sewardj64e1d652004-07-12 14:00:46 +00006425
6426
6427static
6428void codegen_xchg_eAX_Reg ( Int sz, Int reg )
6429{
6430 IRType ty = szToITy(sz);
6431 IRTemp t1 = newTemp(ty);
6432 IRTemp t2 = newTemp(ty);
6433 vassert(sz == 2 || sz == 4);
6434 assign( t1, getIReg(sz, R_EAX) );
6435 assign( t2, getIReg(sz, reg) );
6436 putIReg( sz, R_EAX, mkexpr(t2) );
6437 putIReg( sz, reg, mkexpr(t1) );
6438 DIP("xchg%c %s, %s\n",
6439 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
6440}
6441
6442
sewardjbdc7d212004-09-09 02:46:40 +00006443static
6444void codegen_SAHF ( void )
6445{
6446 /* Set the flags to:
sewardj2a9ad022004-11-25 02:46:58 +00006447 (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
6448 | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6449 |X86G_CC_MASK_P|X86G_CC_MASK_C)
sewardjbdc7d212004-09-09 02:46:40 +00006450 */
sewardj2a9ad022004-11-25 02:46:58 +00006451 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6452 |X86G_CC_MASK_C|X86G_CC_MASK_P;
sewardjbdc7d212004-09-09 02:46:40 +00006453 IRTemp oldflags = newTemp(Ity_I32);
sewardj2a9ad022004-11-25 02:46:58 +00006454 assign( oldflags, mk_x86g_calculate_eflags_all() );
6455 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj905edbd2007-04-07 12:25:37 +00006456 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006457 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6458 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardjbdc7d212004-09-09 02:46:40 +00006459 binop(Iop_Or32,
sewardj2a9ad022004-11-25 02:46:58 +00006460 binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
sewardjbdc7d212004-09-09 02:46:40 +00006461 binop(Iop_And32,
6462 binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
6463 mkU32(mask_SZACP))
6464 )
6465 ));
sewardja3b7e3a2005-04-05 01:54:19 +00006466 /* Set NDEP even though it isn't used. This makes redundant-PUT
6467 elimination of previous stores to this field work better. */
6468 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjbdc7d212004-09-09 02:46:40 +00006469}
6470
6471
sewardj8dfdc8a2005-10-03 11:39:02 +00006472static
6473void codegen_LAHF ( void )
6474{
6475 /* AH <- EFLAGS(SF:ZF:0:AF:0:PF:1:CF) */
6476 IRExpr* eax_with_hole;
6477 IRExpr* new_byte;
6478 IRExpr* new_eax;
6479 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6480 |X86G_CC_MASK_C|X86G_CC_MASK_P;
6481
6482 IRTemp flags = newTemp(Ity_I32);
6483 assign( flags, mk_x86g_calculate_eflags_all() );
6484
6485 eax_with_hole
6486 = binop(Iop_And32, getIReg(4, R_EAX), mkU32(0xFFFF00FF));
6487 new_byte
6488 = binop(Iop_Or32, binop(Iop_And32, mkexpr(flags), mkU32(mask_SZACP)),
6489 mkU32(1<<1));
6490 new_eax
6491 = binop(Iop_Or32, eax_with_hole,
6492 binop(Iop_Shl32, new_byte, mkU8(8)));
6493 putIReg(4, R_EAX, new_eax);
6494}
6495
sewardj458a6f82004-08-25 12:46:02 +00006496
6497static
6498UInt dis_cmpxchg_G_E ( UChar sorb,
sewardje9d8a262009-07-01 08:06:34 +00006499 Bool locked,
sewardj458a6f82004-08-25 12:46:02 +00006500 Int size,
sewardj52d04912005-07-03 00:52:48 +00006501 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00006502{
sewardjc9a43662004-11-30 18:51:59 +00006503 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006504 Int len;
6505
6506 IRType ty = szToITy(size);
6507 IRTemp acc = newTemp(ty);
6508 IRTemp src = newTemp(ty);
6509 IRTemp dest = newTemp(ty);
6510 IRTemp dest2 = newTemp(ty);
6511 IRTemp acc2 = newTemp(ty);
6512 IRTemp cond8 = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00006513 IRTemp addr = IRTemp_INVALID;
sewardj458a6f82004-08-25 12:46:02 +00006514 UChar rm = getUChar(delta0);
6515
sewardje9d8a262009-07-01 08:06:34 +00006516 /* There are 3 cases to consider:
6517
6518 reg-reg: ignore any lock prefix, generate sequence based
6519 on Mux0X
6520
6521 reg-mem, not locked: ignore any lock prefix, generate sequence
6522 based on Mux0X
6523
6524 reg-mem, locked: use IRCAS
6525 */
sewardj458a6f82004-08-25 12:46:02 +00006526 if (epartIsReg(rm)) {
sewardje9d8a262009-07-01 08:06:34 +00006527 /* case 1 */
sewardj458a6f82004-08-25 12:46:02 +00006528 assign( dest, getIReg(size, eregOfRM(rm)) );
6529 delta0++;
sewardje9d8a262009-07-01 08:06:34 +00006530 assign( src, getIReg(size, gregOfRM(rm)) );
6531 assign( acc, getIReg(size, R_EAX) );
6532 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6533 assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
6534 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
6535 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
6536 putIReg(size, R_EAX, mkexpr(acc2));
6537 putIReg(size, eregOfRM(rm), mkexpr(dest2));
sewardj458a6f82004-08-25 12:46:02 +00006538 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6539 nameIReg(size,gregOfRM(rm)),
6540 nameIReg(size,eregOfRM(rm)) );
sewardje9d8a262009-07-01 08:06:34 +00006541 }
6542 else if (!epartIsReg(rm) && !locked) {
6543 /* case 2 */
sewardj458a6f82004-08-25 12:46:02 +00006544 addr = disAMode ( &len, sorb, delta0, dis_buf );
6545 assign( dest, loadLE(ty, mkexpr(addr)) );
6546 delta0 += len;
sewardje9d8a262009-07-01 08:06:34 +00006547 assign( src, getIReg(size, gregOfRM(rm)) );
6548 assign( acc, getIReg(size, R_EAX) );
6549 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6550 assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
6551 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
6552 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
6553 putIReg(size, R_EAX, mkexpr(acc2));
6554 storeLE( mkexpr(addr), mkexpr(dest2) );
sewardj458a6f82004-08-25 12:46:02 +00006555 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6556 nameIReg(size,gregOfRM(rm)), dis_buf);
6557 }
sewardje9d8a262009-07-01 08:06:34 +00006558 else if (!epartIsReg(rm) && locked) {
6559 /* case 3 */
6560 /* src is new value. acc is expected value. dest is old value.
6561 Compute success from the output of the IRCAS, and steer the
6562 new value for EAX accordingly: in case of success, EAX is
6563 unchanged. */
6564 addr = disAMode ( &len, sorb, delta0, dis_buf );
6565 delta0 += len;
6566 assign( src, getIReg(size, gregOfRM(rm)) );
6567 assign( acc, getIReg(size, R_EAX) );
6568 stmt( IRStmt_CAS(
6569 mkIRCAS( IRTemp_INVALID, dest, Iend_LE, mkexpr(addr),
6570 NULL, mkexpr(acc), NULL, mkexpr(src) )
6571 ));
6572 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6573 assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
6574 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
6575 putIReg(size, R_EAX, mkexpr(acc2));
sewardj40d1d212009-07-12 13:01:17 +00006576 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6577 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardj458a6f82004-08-25 12:46:02 +00006578 }
sewardje9d8a262009-07-01 08:06:34 +00006579 else vassert(0);
sewardj458a6f82004-08-25 12:46:02 +00006580
6581 return delta0;
6582}
6583
6584
sewardj458a6f82004-08-25 12:46:02 +00006585/* Handle conditional move instructions of the form
6586 cmovcc E(reg-or-mem), G(reg)
6587
6588 E(src) is reg-or-mem
6589 G(dst) is reg.
6590
6591 If E is reg, --> GET %E, tmps
6592 GET %G, tmpd
6593 CMOVcc tmps, tmpd
6594 PUT tmpd, %G
6595
6596 If E is mem --> (getAddr E) -> tmpa
6597 LD (tmpa), tmps
6598 GET %G, tmpd
6599 CMOVcc tmps, tmpd
6600 PUT tmpd, %G
6601*/
6602static
6603UInt dis_cmov_E_G ( UChar sorb,
6604 Int sz,
sewardj2a9ad022004-11-25 02:46:58 +00006605 X86Condcode cond,
sewardj52d04912005-07-03 00:52:48 +00006606 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00006607{
6608 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006609 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006610 Int len;
6611
sewardj883b00b2004-09-11 09:30:24 +00006612 IRType ty = szToITy(sz);
sewardj458a6f82004-08-25 12:46:02 +00006613 IRTemp tmps = newTemp(ty);
6614 IRTemp tmpd = newTemp(ty);
6615
6616 if (epartIsReg(rm)) {
6617 assign( tmps, getIReg(sz, eregOfRM(rm)) );
6618 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6619
6620 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006621 IRExpr_Mux0X( unop(Iop_1Uto8,
6622 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006623 mkexpr(tmpd),
6624 mkexpr(tmps) )
6625 );
6626 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006627 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006628 nameIReg(sz,eregOfRM(rm)),
6629 nameIReg(sz,gregOfRM(rm)));
6630 return 1+delta0;
6631 }
6632
6633 /* E refers to memory */
6634 {
6635 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6636 assign( tmps, loadLE(ty, mkexpr(addr)) );
6637 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6638
6639 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006640 IRExpr_Mux0X( unop(Iop_1Uto8,
6641 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006642 mkexpr(tmpd),
6643 mkexpr(tmps) )
6644 );
6645
6646 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006647 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006648 dis_buf,
6649 nameIReg(sz,gregOfRM(rm)));
6650 return len+delta0;
6651 }
6652}
6653
6654
sewardj883b00b2004-09-11 09:30:24 +00006655static
sewardje9d8a262009-07-01 08:06:34 +00006656UInt dis_xadd_G_E ( UChar sorb, Bool locked, Int sz, Int delta0,
6657 Bool* decodeOK )
sewardj883b00b2004-09-11 09:30:24 +00006658{
6659 Int len;
6660 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006661 HChar dis_buf[50];
sewardj883b00b2004-09-11 09:30:24 +00006662
sewardj883b00b2004-09-11 09:30:24 +00006663 IRType ty = szToITy(sz);
6664 IRTemp tmpd = newTemp(ty);
6665 IRTemp tmpt0 = newTemp(ty);
6666 IRTemp tmpt1 = newTemp(ty);
6667
sewardje9d8a262009-07-01 08:06:34 +00006668 /* There are 3 cases to consider:
6669
sewardjc2433a82010-05-10 20:51:22 +00006670 reg-reg: ignore any lock prefix,
6671 generate 'naive' (non-atomic) sequence
sewardje9d8a262009-07-01 08:06:34 +00006672
6673 reg-mem, not locked: ignore any lock prefix, generate 'naive'
6674 (non-atomic) sequence
6675
6676 reg-mem, locked: use IRCAS
6677 */
6678
sewardj883b00b2004-09-11 09:30:24 +00006679 if (epartIsReg(rm)) {
sewardje9d8a262009-07-01 08:06:34 +00006680 /* case 1 */
sewardjc2433a82010-05-10 20:51:22 +00006681 assign( tmpd, getIReg(sz, eregOfRM(rm)));
6682 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6683 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6684 mkexpr(tmpd), mkexpr(tmpt0)) );
6685 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6686 putIReg(sz, eregOfRM(rm), mkexpr(tmpt1));
6687 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6688 DIP("xadd%c %s, %s\n",
6689 nameISize(sz), nameIReg(sz,gregOfRM(rm)),
6690 nameIReg(sz,eregOfRM(rm)));
6691 *decodeOK = True;
6692 return 1+delta0;
sewardje9d8a262009-07-01 08:06:34 +00006693 }
6694 else if (!epartIsReg(rm) && !locked) {
6695 /* case 2 */
sewardj883b00b2004-09-11 09:30:24 +00006696 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6697 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6698 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
sewardje9d8a262009-07-01 08:06:34 +00006699 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6700 mkexpr(tmpd), mkexpr(tmpt0)) );
sewardj883b00b2004-09-11 09:30:24 +00006701 storeLE( mkexpr(addr), mkexpr(tmpt1) );
sewardje9d8a262009-07-01 08:06:34 +00006702 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
sewardj883b00b2004-09-11 09:30:24 +00006703 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6704 DIP("xadd%c %s, %s\n",
6705 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
sewardj0092e0d2006-03-06 13:35:42 +00006706 *decodeOK = True;
sewardj883b00b2004-09-11 09:30:24 +00006707 return len+delta0;
6708 }
sewardje9d8a262009-07-01 08:06:34 +00006709 else if (!epartIsReg(rm) && locked) {
6710 /* case 3 */
6711 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6712 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6713 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6714 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6715 mkexpr(tmpd), mkexpr(tmpt0)) );
6716 casLE( mkexpr(addr), mkexpr(tmpd)/*expVal*/,
6717 mkexpr(tmpt1)/*newVal*/, guest_EIP_curr_instr );
6718 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6719 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6720 DIP("xadd%c %s, %s\n",
6721 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6722 *decodeOK = True;
6723 return len+delta0;
6724 }
6725 /*UNREACHED*/
6726 vassert(0);
sewardj883b00b2004-09-11 09:30:24 +00006727}
6728
sewardjb64821b2004-12-14 10:00:16 +00006729/* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
6730
sewardj7df596b2004-12-06 14:29:12 +00006731static
sewardj52d04912005-07-03 00:52:48 +00006732UInt dis_mov_Ew_Sw ( UChar sorb, Int delta0 )
sewardj7df596b2004-12-06 14:29:12 +00006733{
sewardjb64821b2004-12-14 10:00:16 +00006734 Int len;
6735 IRTemp addr;
6736 UChar rm = getIByte(delta0);
6737 HChar dis_buf[50];
sewardj7df596b2004-12-06 14:29:12 +00006738
6739 if (epartIsReg(rm)) {
6740 putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
6741 DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
6742 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006743 } else {
6744 addr = disAMode ( &len, sorb, delta0, dis_buf );
6745 putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
6746 DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
6747 return len+delta0;
sewardj7df596b2004-12-06 14:29:12 +00006748 }
6749}
6750
sewardjb64821b2004-12-14 10:00:16 +00006751/* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
6752 dst is ireg and sz==4, zero out top half of it. */
6753
sewardj063f02f2004-10-20 12:36:12 +00006754static
6755UInt dis_mov_Sw_Ew ( UChar sorb,
6756 Int sz,
sewardj52d04912005-07-03 00:52:48 +00006757 Int delta0 )
sewardj063f02f2004-10-20 12:36:12 +00006758{
sewardjb64821b2004-12-14 10:00:16 +00006759 Int len;
6760 IRTemp addr;
6761 UChar rm = getIByte(delta0);
6762 HChar dis_buf[50];
sewardj063f02f2004-10-20 12:36:12 +00006763
6764 vassert(sz == 2 || sz == 4);
6765
6766 if (epartIsReg(rm)) {
6767 if (sz == 4)
6768 putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6769 else
6770 putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6771
6772 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6773 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006774 } else {
6775 addr = disAMode ( &len, sorb, delta0, dis_buf );
6776 storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
sewardj063f02f2004-10-20 12:36:12 +00006777 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
sewardjb64821b2004-12-14 10:00:16 +00006778 return len+delta0;
sewardj063f02f2004-10-20 12:36:12 +00006779 }
sewardj063f02f2004-10-20 12:36:12 +00006780}
6781
6782
sewardjb64821b2004-12-14 10:00:16 +00006783static
6784void dis_push_segreg ( UInt sreg, Int sz )
6785{
6786 IRTemp t1 = newTemp(Ity_I16);
6787 IRTemp ta = newTemp(Ity_I32);
6788 vassert(sz == 2 || sz == 4);
6789
6790 assign( t1, getSReg(sreg) );
6791 assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6792 putIReg(4, R_ESP, mkexpr(ta));
6793 storeLE( mkexpr(ta), mkexpr(t1) );
6794
sewardj5c5f72c2006-03-18 11:29:25 +00006795 DIP("push%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
sewardjb64821b2004-12-14 10:00:16 +00006796}
6797
6798static
6799void dis_pop_segreg ( UInt sreg, Int sz )
6800{
6801 IRTemp t1 = newTemp(Ity_I16);
6802 IRTemp ta = newTemp(Ity_I32);
6803 vassert(sz == 2 || sz == 4);
6804
6805 assign( ta, getIReg(4, R_ESP) );
6806 assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
6807
6808 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
6809 putSReg( sreg, mkexpr(t1) );
sewardj5c5f72c2006-03-18 11:29:25 +00006810 DIP("pop%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
sewardjb64821b2004-12-14 10:00:16 +00006811}
sewardje05c42c2004-07-08 20:25:10 +00006812
6813static
6814void dis_ret ( UInt d32 )
6815{
6816 IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
6817 assign(t1, getIReg(4,R_ESP));
6818 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6819 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardj78c19df2004-07-12 22:49:27 +00006820 jmp_treg(Ijk_Ret,t2);
sewardje05c42c2004-07-08 20:25:10 +00006821}
6822
sewardj4cb918d2004-12-03 19:43:31 +00006823/*------------------------------------------------------------*/
6824/*--- SSE/SSE2/SSE3 helpers ---*/
6825/*------------------------------------------------------------*/
sewardjc9a43662004-11-30 18:51:59 +00006826
sewardj129b3d92004-12-05 15:42:05 +00006827/* Worker function; do not call directly.
6828 Handles full width G = G `op` E and G = (not G) `op` E.
6829*/
6830
6831static UInt dis_SSE_E_to_G_all_wrk (
sewardj52d04912005-07-03 00:52:48 +00006832 UChar sorb, Int delta,
sewardj1e6ad742004-12-02 16:16:11 +00006833 HChar* opname, IROp op,
6834 Bool invertG
6835 )
sewardjc9a43662004-11-30 18:51:59 +00006836{
sewardj1e6ad742004-12-02 16:16:11 +00006837 HChar dis_buf[50];
6838 Int alen;
6839 IRTemp addr;
6840 UChar rm = getIByte(delta);
6841 IRExpr* gpart
sewardjf0c1c582005-02-07 23:47:38 +00006842 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRM(rm)))
sewardj1e6ad742004-12-02 16:16:11 +00006843 : getXMMReg(gregOfRM(rm));
sewardjc9a43662004-11-30 18:51:59 +00006844 if (epartIsReg(rm)) {
6845 putXMMReg( gregOfRM(rm),
sewardj1e6ad742004-12-02 16:16:11 +00006846 binop(op, gpart,
6847 getXMMReg(eregOfRM(rm))) );
sewardjc9a43662004-11-30 18:51:59 +00006848 DIP("%s %s,%s\n", opname,
6849 nameXMMReg(eregOfRM(rm)),
6850 nameXMMReg(gregOfRM(rm)) );
6851 return delta+1;
6852 } else {
sewardj1e6ad742004-12-02 16:16:11 +00006853 addr = disAMode ( &alen, sorb, delta, dis_buf );
6854 putXMMReg( gregOfRM(rm),
6855 binop(op, gpart,
6856 loadLE(Ity_V128, mkexpr(addr))) );
6857 DIP("%s %s,%s\n", opname,
6858 dis_buf,
6859 nameXMMReg(gregOfRM(rm)) );
6860 return delta+alen;
sewardjc9a43662004-11-30 18:51:59 +00006861 }
6862}
6863
sewardj129b3d92004-12-05 15:42:05 +00006864
6865/* All lanes SSE binary operation, G = G `op` E. */
sewardj1e6ad742004-12-02 16:16:11 +00006866
6867static
sewardj52d04912005-07-03 00:52:48 +00006868UInt dis_SSE_E_to_G_all ( UChar sorb, Int delta, HChar* opname, IROp op )
sewardj1e6ad742004-12-02 16:16:11 +00006869{
sewardj129b3d92004-12-05 15:42:05 +00006870 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
sewardj1e6ad742004-12-02 16:16:11 +00006871}
6872
sewardj129b3d92004-12-05 15:42:05 +00006873/* All lanes SSE binary operation, G = (not G) `op` E. */
6874
6875static
sewardj52d04912005-07-03 00:52:48 +00006876UInt dis_SSE_E_to_G_all_invG ( UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006877 HChar* opname, IROp op )
6878{
6879 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
6880}
6881
sewardj164f9272004-12-09 00:39:32 +00006882
sewardj129b3d92004-12-05 15:42:05 +00006883/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
6884
sewardj52d04912005-07-03 00:52:48 +00006885static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006886 HChar* opname, IROp op )
6887{
6888 HChar dis_buf[50];
6889 Int alen;
6890 IRTemp addr;
6891 UChar rm = getIByte(delta);
6892 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6893 if (epartIsReg(rm)) {
6894 putXMMReg( gregOfRM(rm),
6895 binop(op, gpart,
6896 getXMMReg(eregOfRM(rm))) );
6897 DIP("%s %s,%s\n", opname,
6898 nameXMMReg(eregOfRM(rm)),
6899 nameXMMReg(gregOfRM(rm)) );
6900 return delta+1;
6901 } else {
6902 /* We can only do a 32-bit memory read, so the upper 3/4 of the
6903 E operand needs to be made simply of zeroes. */
6904 IRTemp epart = newTemp(Ity_V128);
6905 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00006906 assign( epart, unop( Iop_32UtoV128,
sewardj129b3d92004-12-05 15:42:05 +00006907 loadLE(Ity_I32, mkexpr(addr))) );
6908 putXMMReg( gregOfRM(rm),
6909 binop(op, gpart, mkexpr(epart)) );
6910 DIP("%s %s,%s\n", opname,
6911 dis_buf,
6912 nameXMMReg(gregOfRM(rm)) );
6913 return delta+alen;
6914 }
6915}
6916
sewardj164f9272004-12-09 00:39:32 +00006917
sewardj636ad762004-12-07 11:16:04 +00006918/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
6919
sewardj52d04912005-07-03 00:52:48 +00006920static UInt dis_SSE_E_to_G_lo64 ( UChar sorb, Int delta,
sewardj636ad762004-12-07 11:16:04 +00006921 HChar* opname, IROp op )
6922{
6923 HChar dis_buf[50];
6924 Int alen;
6925 IRTemp addr;
6926 UChar rm = getIByte(delta);
6927 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6928 if (epartIsReg(rm)) {
6929 putXMMReg( gregOfRM(rm),
6930 binop(op, gpart,
6931 getXMMReg(eregOfRM(rm))) );
6932 DIP("%s %s,%s\n", opname,
6933 nameXMMReg(eregOfRM(rm)),
6934 nameXMMReg(gregOfRM(rm)) );
6935 return delta+1;
6936 } else {
6937 /* We can only do a 64-bit memory read, so the upper half of the
6938 E operand needs to be made simply of zeroes. */
6939 IRTemp epart = newTemp(Ity_V128);
6940 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00006941 assign( epart, unop( Iop_64UtoV128,
sewardj636ad762004-12-07 11:16:04 +00006942 loadLE(Ity_I64, mkexpr(addr))) );
6943 putXMMReg( gregOfRM(rm),
6944 binop(op, gpart, mkexpr(epart)) );
6945 DIP("%s %s,%s\n", opname,
6946 dis_buf,
6947 nameXMMReg(gregOfRM(rm)) );
6948 return delta+alen;
6949 }
6950}
6951
sewardj164f9272004-12-09 00:39:32 +00006952
sewardj129b3d92004-12-05 15:42:05 +00006953/* All lanes unary SSE operation, G = op(E). */
6954
6955static UInt dis_SSE_E_to_G_unary_all (
sewardj52d04912005-07-03 00:52:48 +00006956 UChar sorb, Int delta,
sewardj0bd7ce62004-12-05 02:47:40 +00006957 HChar* opname, IROp op
6958 )
6959{
6960 HChar dis_buf[50];
6961 Int alen;
6962 IRTemp addr;
6963 UChar rm = getIByte(delta);
6964 if (epartIsReg(rm)) {
6965 putXMMReg( gregOfRM(rm),
6966 unop(op, getXMMReg(eregOfRM(rm))) );
6967 DIP("%s %s,%s\n", opname,
6968 nameXMMReg(eregOfRM(rm)),
6969 nameXMMReg(gregOfRM(rm)) );
6970 return delta+1;
6971 } else {
6972 addr = disAMode ( &alen, sorb, delta, dis_buf );
6973 putXMMReg( gregOfRM(rm),
6974 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
6975 DIP("%s %s,%s\n", opname,
6976 dis_buf,
6977 nameXMMReg(gregOfRM(rm)) );
6978 return delta+alen;
6979 }
6980}
6981
sewardj164f9272004-12-09 00:39:32 +00006982
sewardj129b3d92004-12-05 15:42:05 +00006983/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
sewardj0bd7ce62004-12-05 02:47:40 +00006984
sewardj129b3d92004-12-05 15:42:05 +00006985static UInt dis_SSE_E_to_G_unary_lo32 (
sewardj52d04912005-07-03 00:52:48 +00006986 UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006987 HChar* opname, IROp op
6988 )
6989{
6990 /* First we need to get the old G value and patch the low 32 bits
6991 of the E operand into it. Then apply op and write back to G. */
6992 HChar dis_buf[50];
6993 Int alen;
6994 IRTemp addr;
6995 UChar rm = getIByte(delta);
6996 IRTemp oldG0 = newTemp(Ity_V128);
6997 IRTemp oldG1 = newTemp(Ity_V128);
6998
6999 assign( oldG0, getXMMReg(gregOfRM(rm)) );
7000
7001 if (epartIsReg(rm)) {
7002 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00007003 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00007004 mkexpr(oldG0),
sewardj35579be2004-12-06 00:36:25 +00007005 getXMMRegLane32(eregOfRM(rm), 0)) );
sewardj129b3d92004-12-05 15:42:05 +00007006 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7007 DIP("%s %s,%s\n", opname,
7008 nameXMMReg(eregOfRM(rm)),
7009 nameXMMReg(gregOfRM(rm)) );
7010 return delta+1;
7011 } else {
7012 addr = disAMode ( &alen, sorb, delta, dis_buf );
7013 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00007014 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00007015 mkexpr(oldG0),
7016 loadLE(Ity_I32, mkexpr(addr)) ));
7017 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7018 DIP("%s %s,%s\n", opname,
7019 dis_buf,
7020 nameXMMReg(gregOfRM(rm)) );
7021 return delta+alen;
7022 }
7023}
7024
sewardj164f9272004-12-09 00:39:32 +00007025
sewardj008754b2004-12-08 14:37:10 +00007026/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7027
7028static UInt dis_SSE_E_to_G_unary_lo64 (
sewardj52d04912005-07-03 00:52:48 +00007029 UChar sorb, Int delta,
sewardj008754b2004-12-08 14:37:10 +00007030 HChar* opname, IROp op
7031 )
7032{
7033 /* First we need to get the old G value and patch the low 64 bits
7034 of the E operand into it. Then apply op and write back to G. */
7035 HChar dis_buf[50];
7036 Int alen;
7037 IRTemp addr;
7038 UChar rm = getIByte(delta);
7039 IRTemp oldG0 = newTemp(Ity_V128);
7040 IRTemp oldG1 = newTemp(Ity_V128);
7041
7042 assign( oldG0, getXMMReg(gregOfRM(rm)) );
7043
7044 if (epartIsReg(rm)) {
7045 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00007046 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00007047 mkexpr(oldG0),
7048 getXMMRegLane64(eregOfRM(rm), 0)) );
7049 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7050 DIP("%s %s,%s\n", opname,
7051 nameXMMReg(eregOfRM(rm)),
7052 nameXMMReg(gregOfRM(rm)) );
7053 return delta+1;
7054 } else {
7055 addr = disAMode ( &alen, sorb, delta, dis_buf );
7056 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00007057 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00007058 mkexpr(oldG0),
7059 loadLE(Ity_I64, mkexpr(addr)) ));
7060 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7061 DIP("%s %s,%s\n", opname,
7062 dis_buf,
7063 nameXMMReg(gregOfRM(rm)) );
7064 return delta+alen;
7065 }
7066}
7067
sewardj164f9272004-12-09 00:39:32 +00007068
7069/* SSE integer binary operation:
7070 G = G `op` E (eLeft == False)
7071 G = E `op` G (eLeft == True)
7072*/
7073static UInt dis_SSEint_E_to_G(
sewardj52d04912005-07-03 00:52:48 +00007074 UChar sorb, Int delta,
sewardj164f9272004-12-09 00:39:32 +00007075 HChar* opname, IROp op,
7076 Bool eLeft
7077 )
7078{
7079 HChar dis_buf[50];
7080 Int alen;
7081 IRTemp addr;
7082 UChar rm = getIByte(delta);
7083 IRExpr* gpart = getXMMReg(gregOfRM(rm));
7084 IRExpr* epart = NULL;
7085 if (epartIsReg(rm)) {
7086 epart = getXMMReg(eregOfRM(rm));
7087 DIP("%s %s,%s\n", opname,
7088 nameXMMReg(eregOfRM(rm)),
7089 nameXMMReg(gregOfRM(rm)) );
7090 delta += 1;
7091 } else {
7092 addr = disAMode ( &alen, sorb, delta, dis_buf );
7093 epart = loadLE(Ity_V128, mkexpr(addr));
7094 DIP("%s %s,%s\n", opname,
7095 dis_buf,
7096 nameXMMReg(gregOfRM(rm)) );
7097 delta += alen;
7098 }
7099 putXMMReg( gregOfRM(rm),
7100 eLeft ? binop(op, epart, gpart)
7101 : binop(op, gpart, epart) );
7102 return delta;
7103}
7104
7105
sewardjfd226452004-12-07 19:02:18 +00007106/* Helper for doing SSE FP comparisons. */
sewardj0bd7ce62004-12-05 02:47:40 +00007107
sewardj1e6ad742004-12-02 16:16:11 +00007108static void findSSECmpOp ( Bool* needNot, IROp* op,
7109 Int imm8, Bool all_lanes, Int sz )
7110{
7111 imm8 &= 7;
7112 *needNot = False;
7113 *op = Iop_INVALID;
7114 if (imm8 >= 4) {
7115 *needNot = True;
7116 imm8 -= 4;
7117 }
7118
7119 if (sz == 4 && all_lanes) {
7120 switch (imm8) {
7121 case 0: *op = Iop_CmpEQ32Fx4; return;
7122 case 1: *op = Iop_CmpLT32Fx4; return;
7123 case 2: *op = Iop_CmpLE32Fx4; return;
7124 case 3: *op = Iop_CmpUN32Fx4; return;
7125 default: break;
7126 }
7127 }
7128 if (sz == 4 && !all_lanes) {
7129 switch (imm8) {
7130 case 0: *op = Iop_CmpEQ32F0x4; return;
7131 case 1: *op = Iop_CmpLT32F0x4; return;
7132 case 2: *op = Iop_CmpLE32F0x4; return;
7133 case 3: *op = Iop_CmpUN32F0x4; return;
7134 default: break;
7135 }
7136 }
sewardjfd226452004-12-07 19:02:18 +00007137 if (sz == 8 && all_lanes) {
7138 switch (imm8) {
7139 case 0: *op = Iop_CmpEQ64Fx2; return;
7140 case 1: *op = Iop_CmpLT64Fx2; return;
7141 case 2: *op = Iop_CmpLE64Fx2; return;
7142 case 3: *op = Iop_CmpUN64Fx2; return;
7143 default: break;
7144 }
7145 }
7146 if (sz == 8 && !all_lanes) {
7147 switch (imm8) {
7148 case 0: *op = Iop_CmpEQ64F0x2; return;
7149 case 1: *op = Iop_CmpLT64F0x2; return;
7150 case 2: *op = Iop_CmpLE64F0x2; return;
7151 case 3: *op = Iop_CmpUN64F0x2; return;
7152 default: break;
7153 }
sewardj1e6ad742004-12-02 16:16:11 +00007154 }
7155 vpanic("findSSECmpOp(x86,guest)");
7156}
7157
sewardj33c69e52006-01-01 17:15:19 +00007158/* Handles SSE 32F/64F comparisons. */
sewardj129b3d92004-12-05 15:42:05 +00007159
sewardj52d04912005-07-03 00:52:48 +00007160static UInt dis_SSEcmp_E_to_G ( UChar sorb, Int delta,
sewardj1e6ad742004-12-02 16:16:11 +00007161 HChar* opname, Bool all_lanes, Int sz )
7162{
7163 HChar dis_buf[50];
7164 Int alen, imm8;
7165 IRTemp addr;
7166 Bool needNot = False;
7167 IROp op = Iop_INVALID;
7168 IRTemp plain = newTemp(Ity_V128);
7169 UChar rm = getIByte(delta);
7170 UShort mask = 0;
7171 vassert(sz == 4 || sz == 8);
7172 if (epartIsReg(rm)) {
7173 imm8 = getIByte(delta+1);
7174 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7175 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
7176 getXMMReg(eregOfRM(rm))) );
7177 delta += 2;
7178 DIP("%s $%d,%s,%s\n", opname,
7179 (Int)imm8,
7180 nameXMMReg(eregOfRM(rm)),
7181 nameXMMReg(gregOfRM(rm)) );
7182 } else {
7183 addr = disAMode ( &alen, sorb, delta, dis_buf );
7184 imm8 = getIByte(delta+alen);
7185 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
sewardj33c69e52006-01-01 17:15:19 +00007186 assign( plain,
7187 binop(
7188 op,
7189 getXMMReg(gregOfRM(rm)),
7190 all_lanes ? loadLE(Ity_V128, mkexpr(addr))
7191 : sz == 8 ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
7192 : /*sz==4*/ unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
7193 )
7194 );
sewardj1e6ad742004-12-02 16:16:11 +00007195 delta += alen+1;
7196 DIP("%s $%d,%s,%s\n", opname,
7197 (Int)imm8,
7198 dis_buf,
7199 nameXMMReg(gregOfRM(rm)) );
7200 }
7201
sewardj2e383862004-12-12 16:46:47 +00007202 if (needNot && all_lanes) {
7203 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00007204 unop(Iop_NotV128, mkexpr(plain)) );
sewardj2e383862004-12-12 16:46:47 +00007205 }
7206 else
7207 if (needNot && !all_lanes) {
sewardj9b45b482005-02-07 01:42:18 +00007208 mask = toUShort( sz==4 ? 0x000F : 0x00FF );
sewardj2e383862004-12-12 16:46:47 +00007209 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00007210 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
sewardj2e383862004-12-12 16:46:47 +00007211 }
7212 else {
7213 putXMMReg( gregOfRM(rm), mkexpr(plain) );
7214 }
sewardj1e6ad742004-12-02 16:16:11 +00007215
sewardj1e6ad742004-12-02 16:16:11 +00007216 return delta;
7217}
7218
sewardjb9fa69b2004-12-09 23:25:14 +00007219
7220/* Vector by scalar shift of G by the amount specified at the bottom
7221 of E. */
7222
sewardj52d04912005-07-03 00:52:48 +00007223static UInt dis_SSE_shiftG_byE ( UChar sorb, Int delta,
sewardjb9fa69b2004-12-09 23:25:14 +00007224 HChar* opname, IROp op )
7225{
7226 HChar dis_buf[50];
7227 Int alen, size;
7228 IRTemp addr;
7229 Bool shl, shr, sar;
7230 UChar rm = getIByte(delta);
7231 IRTemp g0 = newTemp(Ity_V128);
7232 IRTemp g1 = newTemp(Ity_V128);
7233 IRTemp amt = newTemp(Ity_I32);
7234 IRTemp amt8 = newTemp(Ity_I8);
7235 if (epartIsReg(rm)) {
7236 assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
7237 DIP("%s %s,%s\n", opname,
7238 nameXMMReg(eregOfRM(rm)),
7239 nameXMMReg(gregOfRM(rm)) );
7240 delta++;
7241 } else {
7242 addr = disAMode ( &alen, sorb, delta, dis_buf );
7243 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
7244 DIP("%s %s,%s\n", opname,
7245 dis_buf,
7246 nameXMMReg(gregOfRM(rm)) );
7247 delta += alen;
7248 }
7249 assign( g0, getXMMReg(gregOfRM(rm)) );
7250 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
7251
7252 shl = shr = sar = False;
7253 size = 0;
7254 switch (op) {
7255 case Iop_ShlN16x8: shl = True; size = 32; break;
7256 case Iop_ShlN32x4: shl = True; size = 32; break;
7257 case Iop_ShlN64x2: shl = True; size = 64; break;
7258 case Iop_SarN16x8: sar = True; size = 16; break;
7259 case Iop_SarN32x4: sar = True; size = 32; break;
7260 case Iop_ShrN16x8: shr = True; size = 16; break;
7261 case Iop_ShrN32x4: shr = True; size = 32; break;
7262 case Iop_ShrN64x2: shr = True; size = 64; break;
7263 default: vassert(0);
7264 }
7265
7266 if (shl || shr) {
7267 assign(
7268 g1,
7269 IRExpr_Mux0X(
7270 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
7271 mkV128(0x0000),
7272 binop(op, mkexpr(g0), mkexpr(amt8))
7273 )
7274 );
7275 } else
7276 if (sar) {
7277 assign(
7278 g1,
7279 IRExpr_Mux0X(
7280 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
7281 binop(op, mkexpr(g0), mkU8(size-1)),
7282 binop(op, mkexpr(g0), mkexpr(amt8))
7283 )
7284 );
7285 } else {
sewardjba89f4c2005-04-07 17:31:27 +00007286 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00007287 vassert(0);
7288 }
7289
7290 putXMMReg( gregOfRM(rm), mkexpr(g1) );
7291 return delta;
7292}
7293
7294
7295/* Vector by scalar shift of E by an immediate byte. */
7296
sewardj38a3f862005-01-13 15:06:51 +00007297static
sewardj52d04912005-07-03 00:52:48 +00007298UInt dis_SSE_shiftE_imm ( Int delta, HChar* opname, IROp op )
sewardjb9fa69b2004-12-09 23:25:14 +00007299{
7300 Bool shl, shr, sar;
7301 UChar rm = getIByte(delta);
sewardj38a3f862005-01-13 15:06:51 +00007302 IRTemp e0 = newTemp(Ity_V128);
7303 IRTemp e1 = newTemp(Ity_V128);
sewardjb9fa69b2004-12-09 23:25:14 +00007304 UChar amt, size;
7305 vassert(epartIsReg(rm));
7306 vassert(gregOfRM(rm) == 2
7307 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00007308 amt = getIByte(delta+1);
sewardjb9fa69b2004-12-09 23:25:14 +00007309 delta += 2;
7310 DIP("%s $%d,%s\n", opname,
7311 (Int)amt,
7312 nameXMMReg(eregOfRM(rm)) );
sewardj38a3f862005-01-13 15:06:51 +00007313 assign( e0, getXMMReg(eregOfRM(rm)) );
sewardjb9fa69b2004-12-09 23:25:14 +00007314
7315 shl = shr = sar = False;
7316 size = 0;
7317 switch (op) {
7318 case Iop_ShlN16x8: shl = True; size = 16; break;
7319 case Iop_ShlN32x4: shl = True; size = 32; break;
7320 case Iop_ShlN64x2: shl = True; size = 64; break;
7321 case Iop_SarN16x8: sar = True; size = 16; break;
7322 case Iop_SarN32x4: sar = True; size = 32; break;
7323 case Iop_ShrN16x8: shr = True; size = 16; break;
7324 case Iop_ShrN32x4: shr = True; size = 32; break;
7325 case Iop_ShrN64x2: shr = True; size = 64; break;
7326 default: vassert(0);
7327 }
7328
7329 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00007330 assign( e1, amt >= size
7331 ? mkV128(0x0000)
7332 : binop(op, mkexpr(e0), mkU8(amt))
7333 );
sewardjb9fa69b2004-12-09 23:25:14 +00007334 } else
7335 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00007336 assign( e1, amt >= size
7337 ? binop(op, mkexpr(e0), mkU8(size-1))
7338 : binop(op, mkexpr(e0), mkU8(amt))
7339 );
sewardjb9fa69b2004-12-09 23:25:14 +00007340 } else {
sewardjba89f4c2005-04-07 17:31:27 +00007341 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00007342 vassert(0);
7343 }
7344
sewardj38a3f862005-01-13 15:06:51 +00007345 putXMMReg( eregOfRM(rm), mkexpr(e1) );
sewardjb9fa69b2004-12-09 23:25:14 +00007346 return delta;
7347}
7348
7349
sewardjc1e7dfc2004-12-05 19:29:45 +00007350/* Get the current SSE rounding mode. */
sewardjc9a65702004-07-07 16:32:57 +00007351
sewardj4cb918d2004-12-03 19:43:31 +00007352static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
7353{
7354 return binop( Iop_And32,
7355 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
7356 mkU32(3) );
7357}
7358
sewardj636ad762004-12-07 11:16:04 +00007359static void put_sse_roundingmode ( IRExpr* sseround )
7360{
sewardjdd40fdf2006-12-24 02:20:24 +00007361 vassert(typeOfIRExpr(irsb->tyenv, sseround) == Ity_I32);
sewardj636ad762004-12-07 11:16:04 +00007362 stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
7363}
7364
sewardjc1e7dfc2004-12-05 19:29:45 +00007365/* Break a 128-bit value up into four 32-bit ints. */
7366
7367static void breakup128to32s ( IRTemp t128,
7368 /*OUTs*/
7369 IRTemp* t3, IRTemp* t2,
7370 IRTemp* t1, IRTemp* t0 )
7371{
7372 IRTemp hi64 = newTemp(Ity_I64);
7373 IRTemp lo64 = newTemp(Ity_I64);
sewardjf0c1c582005-02-07 23:47:38 +00007374 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
7375 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
sewardjc1e7dfc2004-12-05 19:29:45 +00007376
7377 vassert(t0 && *t0 == IRTemp_INVALID);
7378 vassert(t1 && *t1 == IRTemp_INVALID);
7379 vassert(t2 && *t2 == IRTemp_INVALID);
7380 vassert(t3 && *t3 == IRTemp_INVALID);
7381
7382 *t0 = newTemp(Ity_I32);
7383 *t1 = newTemp(Ity_I32);
7384 *t2 = newTemp(Ity_I32);
7385 *t3 = newTemp(Ity_I32);
7386 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
7387 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
7388 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
7389 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
7390}
7391
7392/* Construct a 128-bit value from four 32-bit ints. */
7393
7394static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
7395 IRTemp t1, IRTemp t0 )
7396{
7397 return
sewardjf0c1c582005-02-07 23:47:38 +00007398 binop( Iop_64HLtoV128,
sewardjc1e7dfc2004-12-05 19:29:45 +00007399 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
7400 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
7401 );
7402}
7403
sewardjb9fa69b2004-12-09 23:25:14 +00007404/* Break a 64-bit value up into four 16-bit ints. */
7405
7406static void breakup64to16s ( IRTemp t64,
7407 /*OUTs*/
7408 IRTemp* t3, IRTemp* t2,
7409 IRTemp* t1, IRTemp* t0 )
7410{
7411 IRTemp hi32 = newTemp(Ity_I32);
7412 IRTemp lo32 = newTemp(Ity_I32);
7413 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
7414 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
7415
7416 vassert(t0 && *t0 == IRTemp_INVALID);
7417 vassert(t1 && *t1 == IRTemp_INVALID);
7418 vassert(t2 && *t2 == IRTemp_INVALID);
7419 vassert(t3 && *t3 == IRTemp_INVALID);
7420
7421 *t0 = newTemp(Ity_I16);
7422 *t1 = newTemp(Ity_I16);
7423 *t2 = newTemp(Ity_I16);
7424 *t3 = newTemp(Ity_I16);
7425 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
7426 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
7427 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
7428 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
7429}
7430
7431/* Construct a 64-bit value from four 16-bit ints. */
7432
7433static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
7434 IRTemp t1, IRTemp t0 )
7435{
7436 return
7437 binop( Iop_32HLto64,
7438 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7439 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7440 );
7441}
7442
sewardj0e9a0f52008-01-04 01:22:41 +00007443/* Generate IR to set the guest %EFLAGS from the pushfl-format image
7444 in the given 32-bit temporary. The flags that are set are: O S Z A
7445 C P D ID AC.
7446
7447 In all cases, code to set AC is generated. However, VEX actually
7448 ignores the AC value and so can optionally emit an emulation
7449 warning when it is enabled. In this routine, an emulation warning
7450 is only emitted if emit_AC_emwarn is True, in which case
7451 next_insn_EIP must be correct (this allows for correct code
7452 generation for popfl/popfw). If emit_AC_emwarn is False,
7453 next_insn_EIP is unimportant (this allows for easy if kludgey code
7454 generation for IRET.) */
7455
7456static
7457void set_EFLAGS_from_value ( IRTemp t1,
7458 Bool emit_AC_emwarn,
7459 Addr32 next_insn_EIP )
7460{
7461 vassert(typeOfIRTemp(irsb->tyenv,t1) == Ity_I32);
7462
7463 /* t1 is the flag word. Mask out everything except OSZACP and set
7464 the flags thunk to X86G_CC_OP_COPY. */
7465 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7466 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7467 stmt( IRStmt_Put( OFFB_CC_DEP1,
7468 binop(Iop_And32,
7469 mkexpr(t1),
7470 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
7471 | X86G_CC_MASK_A | X86G_CC_MASK_Z
7472 | X86G_CC_MASK_S| X86G_CC_MASK_O )
7473 )
7474 )
7475 );
7476 /* Set NDEP even though it isn't used. This makes redundant-PUT
7477 elimination of previous stores to this field work better. */
7478 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
7479
7480 /* Also need to set the D flag, which is held in bit 10 of t1.
7481 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
7482 stmt( IRStmt_Put(
7483 OFFB_DFLAG,
7484 IRExpr_Mux0X(
7485 unop(Iop_32to8,
7486 binop(Iop_And32,
7487 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
7488 mkU32(1))),
7489 mkU32(1),
7490 mkU32(0xFFFFFFFF)))
7491 );
7492
7493 /* Set the ID flag */
7494 stmt( IRStmt_Put(
7495 OFFB_IDFLAG,
7496 IRExpr_Mux0X(
7497 unop(Iop_32to8,
7498 binop(Iop_And32,
7499 binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
7500 mkU32(1))),
7501 mkU32(0),
7502 mkU32(1)))
7503 );
7504
7505 /* And set the AC flag. If setting it 1 to, possibly emit an
7506 emulation warning. */
7507 stmt( IRStmt_Put(
7508 OFFB_ACFLAG,
7509 IRExpr_Mux0X(
7510 unop(Iop_32to8,
7511 binop(Iop_And32,
7512 binop(Iop_Shr32, mkexpr(t1), mkU8(18)),
7513 mkU32(1))),
7514 mkU32(0),
7515 mkU32(1)))
7516 );
7517
7518 if (emit_AC_emwarn) {
7519 put_emwarn( mkU32(EmWarn_X86_acFlag) );
7520 stmt(
7521 IRStmt_Exit(
7522 binop( Iop_CmpNE32,
7523 binop(Iop_And32, mkexpr(t1), mkU32(1<<18)),
7524 mkU32(0) ),
7525 Ijk_EmWarn,
7526 IRConst_U32( next_insn_EIP )
7527 )
7528 );
7529 }
7530}
7531
sewardj4cb918d2004-12-03 19:43:31 +00007532
sewardj150c9cd2008-02-09 01:16:02 +00007533/* Helper for the SSSE3 (not SSE3) PMULHRSW insns. Given two 64-bit
7534 values (aa,bb), computes, for each of the 4 16-bit lanes:
7535
7536 (((aa_lane *s32 bb_lane) >>u 14) + 1) >>u 1
7537*/
7538static IRExpr* dis_PMULHRSW_helper ( IRExpr* aax, IRExpr* bbx )
7539{
7540 IRTemp aa = newTemp(Ity_I64);
7541 IRTemp bb = newTemp(Ity_I64);
7542 IRTemp aahi32s = newTemp(Ity_I64);
7543 IRTemp aalo32s = newTemp(Ity_I64);
7544 IRTemp bbhi32s = newTemp(Ity_I64);
7545 IRTemp bblo32s = newTemp(Ity_I64);
7546 IRTemp rHi = newTemp(Ity_I64);
7547 IRTemp rLo = newTemp(Ity_I64);
7548 IRTemp one32x2 = newTemp(Ity_I64);
7549 assign(aa, aax);
7550 assign(bb, bbx);
7551 assign( aahi32s,
7552 binop(Iop_SarN32x2,
7553 binop(Iop_InterleaveHI16x4, mkexpr(aa), mkexpr(aa)),
7554 mkU8(16) ));
7555 assign( aalo32s,
7556 binop(Iop_SarN32x2,
7557 binop(Iop_InterleaveLO16x4, mkexpr(aa), mkexpr(aa)),
7558 mkU8(16) ));
7559 assign( bbhi32s,
7560 binop(Iop_SarN32x2,
7561 binop(Iop_InterleaveHI16x4, mkexpr(bb), mkexpr(bb)),
7562 mkU8(16) ));
7563 assign( bblo32s,
7564 binop(Iop_SarN32x2,
7565 binop(Iop_InterleaveLO16x4, mkexpr(bb), mkexpr(bb)),
7566 mkU8(16) ));
7567 assign(one32x2, mkU64( (1ULL << 32) + 1 ));
7568 assign(
7569 rHi,
7570 binop(
7571 Iop_ShrN32x2,
7572 binop(
7573 Iop_Add32x2,
7574 binop(
7575 Iop_ShrN32x2,
7576 binop(Iop_Mul32x2, mkexpr(aahi32s), mkexpr(bbhi32s)),
7577 mkU8(14)
7578 ),
7579 mkexpr(one32x2)
7580 ),
7581 mkU8(1)
7582 )
7583 );
7584 assign(
7585 rLo,
7586 binop(
7587 Iop_ShrN32x2,
7588 binop(
7589 Iop_Add32x2,
7590 binop(
7591 Iop_ShrN32x2,
7592 binop(Iop_Mul32x2, mkexpr(aalo32s), mkexpr(bblo32s)),
7593 mkU8(14)
7594 ),
7595 mkexpr(one32x2)
7596 ),
7597 mkU8(1)
7598 )
7599 );
7600 return
7601 binop(Iop_CatEvenLanes16x4, mkexpr(rHi), mkexpr(rLo));
7602}
7603
7604/* Helper for the SSSE3 (not SSE3) PSIGN{B,W,D} insns. Given two 64-bit
7605 values (aa,bb), computes, for each lane:
7606
7607 if aa_lane < 0 then - bb_lane
7608 else if aa_lane > 0 then bb_lane
7609 else 0
7610*/
7611static IRExpr* dis_PSIGN_helper ( IRExpr* aax, IRExpr* bbx, Int laneszB )
7612{
7613 IRTemp aa = newTemp(Ity_I64);
7614 IRTemp bb = newTemp(Ity_I64);
7615 IRTemp zero = newTemp(Ity_I64);
7616 IRTemp bbNeg = newTemp(Ity_I64);
7617 IRTemp negMask = newTemp(Ity_I64);
7618 IRTemp posMask = newTemp(Ity_I64);
7619 IROp opSub = Iop_INVALID;
7620 IROp opCmpGTS = Iop_INVALID;
7621
7622 switch (laneszB) {
7623 case 1: opSub = Iop_Sub8x8; opCmpGTS = Iop_CmpGT8Sx8; break;
7624 case 2: opSub = Iop_Sub16x4; opCmpGTS = Iop_CmpGT16Sx4; break;
7625 case 4: opSub = Iop_Sub32x2; opCmpGTS = Iop_CmpGT32Sx2; break;
7626 default: vassert(0);
7627 }
7628
7629 assign( aa, aax );
7630 assign( bb, bbx );
7631 assign( zero, mkU64(0) );
7632 assign( bbNeg, binop(opSub, mkexpr(zero), mkexpr(bb)) );
7633 assign( negMask, binop(opCmpGTS, mkexpr(zero), mkexpr(aa)) );
7634 assign( posMask, binop(opCmpGTS, mkexpr(aa), mkexpr(zero)) );
7635
7636 return
7637 binop(Iop_Or64,
7638 binop(Iop_And64, mkexpr(bb), mkexpr(posMask)),
7639 binop(Iop_And64, mkexpr(bbNeg), mkexpr(negMask)) );
7640
7641}
7642
7643/* Helper for the SSSE3 (not SSE3) PABS{B,W,D} insns. Given a 64-bit
7644 value aa, computes, for each lane
7645
7646 if aa < 0 then -aa else aa
7647
7648 Note that the result is interpreted as unsigned, so that the
7649 absolute value of the most negative signed input can be
7650 represented.
7651*/
7652static IRExpr* dis_PABS_helper ( IRExpr* aax, Int laneszB )
7653{
7654 IRTemp aa = newTemp(Ity_I64);
7655 IRTemp zero = newTemp(Ity_I64);
7656 IRTemp aaNeg = newTemp(Ity_I64);
7657 IRTemp negMask = newTemp(Ity_I64);
7658 IRTemp posMask = newTemp(Ity_I64);
7659 IROp opSub = Iop_INVALID;
7660 IROp opSarN = Iop_INVALID;
7661
7662 switch (laneszB) {
7663 case 1: opSub = Iop_Sub8x8; opSarN = Iop_SarN8x8; break;
7664 case 2: opSub = Iop_Sub16x4; opSarN = Iop_SarN16x4; break;
7665 case 4: opSub = Iop_Sub32x2; opSarN = Iop_SarN32x2; break;
7666 default: vassert(0);
7667 }
7668
7669 assign( aa, aax );
7670 assign( negMask, binop(opSarN, mkexpr(aa), mkU8(8*laneszB-1)) );
7671 assign( posMask, unop(Iop_Not64, mkexpr(negMask)) );
7672 assign( zero, mkU64(0) );
7673 assign( aaNeg, binop(opSub, mkexpr(zero), mkexpr(aa)) );
7674 return
7675 binop(Iop_Or64,
7676 binop(Iop_And64, mkexpr(aa), mkexpr(posMask)),
7677 binop(Iop_And64, mkexpr(aaNeg), mkexpr(negMask)) );
7678}
7679
7680static IRExpr* dis_PALIGNR_XMM_helper ( IRTemp hi64,
7681 IRTemp lo64, Int byteShift )
7682{
7683 vassert(byteShift >= 1 && byteShift <= 7);
7684 return
7685 binop(Iop_Or64,
7686 binop(Iop_Shl64, mkexpr(hi64), mkU8(8*(8-byteShift))),
7687 binop(Iop_Shr64, mkexpr(lo64), mkU8(8*byteShift))
7688 );
7689}
7690
7691/* Generate a SIGSEGV followed by a restart of the current instruction
7692 if effective_addr is not 16-aligned. This is required behaviour
7693 for some SSE3 instructions and all 128-bit SSSE3 instructions.
7694 This assumes that guest_RIP_curr_instr is set correctly! */
7695static void gen_SEGV_if_not_16_aligned ( IRTemp effective_addr )
7696{
7697 stmt(
7698 IRStmt_Exit(
7699 binop(Iop_CmpNE32,
7700 binop(Iop_And32,mkexpr(effective_addr),mkU32(0xF)),
7701 mkU32(0)),
7702 Ijk_SigSEGV,
7703 IRConst_U32(guest_EIP_curr_instr)
7704 )
7705 );
7706}
7707
7708
sewardjc4356f02007-11-09 21:15:04 +00007709/* Helper for deciding whether a given insn (starting at the opcode
7710 byte) may validly be used with a LOCK prefix. The following insns
7711 may be used with LOCK when their destination operand is in memory.
sewardje9d8a262009-07-01 08:06:34 +00007712 AFAICS this is exactly the same for both 32-bit and 64-bit mode.
sewardjc4356f02007-11-09 21:15:04 +00007713
sewardje9d8a262009-07-01 08:06:34 +00007714 ADD 80 /0, 81 /0, 82 /0, 83 /0, 00, 01
7715 OR 80 /1, 81 /1, 82 /x, 83 /1, 08, 09
7716 ADC 80 /2, 81 /2, 82 /2, 83 /2, 10, 11
7717 SBB 81 /3, 81 /3, 82 /x, 83 /3, 18, 19
7718 AND 80 /4, 81 /4, 82 /x, 83 /4, 20, 21
7719 SUB 80 /5, 81 /5, 82 /x, 83 /5, 28, 29
7720 XOR 80 /6, 81 /6, 82 /x, 83 /6, 30, 31
sewardjc4356f02007-11-09 21:15:04 +00007721
7722 DEC FE /1, FF /1
7723 INC FE /0, FF /0
7724
7725 NEG F6 /3, F7 /3
7726 NOT F6 /2, F7 /2
7727
sewardje9d8a262009-07-01 08:06:34 +00007728 XCHG 86, 87
sewardjc4356f02007-11-09 21:15:04 +00007729
7730 BTC 0F BB, 0F BA /7
7731 BTR 0F B3, 0F BA /6
7732 BTS 0F AB, 0F BA /5
7733
7734 CMPXCHG 0F B0, 0F B1
7735 CMPXCHG8B 0F C7 /1
7736
7737 XADD 0F C0, 0F C1
sewardje9d8a262009-07-01 08:06:34 +00007738
7739 ------------------------------
7740
7741 80 /0 = addb $imm8, rm8
7742 81 /0 = addl $imm32, rm32 and addw $imm16, rm16
7743 82 /0 = addb $imm8, rm8
7744 83 /0 = addl $simm8, rm32 and addw $simm8, rm16
7745
7746 00 = addb r8, rm8
7747 01 = addl r32, rm32 and addw r16, rm16
7748
7749 Same for ADD OR ADC SBB AND SUB XOR
7750
7751 FE /1 = dec rm8
7752 FF /1 = dec rm32 and dec rm16
7753
7754 FE /0 = inc rm8
7755 FF /0 = inc rm32 and inc rm16
7756
7757 F6 /3 = neg rm8
7758 F7 /3 = neg rm32 and neg rm16
7759
7760 F6 /2 = not rm8
7761 F7 /2 = not rm32 and not rm16
7762
7763 0F BB = btcw r16, rm16 and btcl r32, rm32
7764 OF BA /7 = btcw $imm8, rm16 and btcw $imm8, rm32
7765
7766 Same for BTS, BTR
sewardjc4356f02007-11-09 21:15:04 +00007767*/
7768static Bool can_be_used_with_LOCK_prefix ( UChar* opc )
7769{
7770 switch (opc[0]) {
sewardje9d8a262009-07-01 08:06:34 +00007771 case 0x00: case 0x01: case 0x08: case 0x09:
7772 case 0x10: case 0x11: case 0x18: case 0x19:
7773 case 0x20: case 0x21: case 0x28: case 0x29:
7774 case 0x30: case 0x31:
7775 if (!epartIsReg(opc[1]))
7776 return True;
7777 break;
sewardjc4356f02007-11-09 21:15:04 +00007778
sewardje9d8a262009-07-01 08:06:34 +00007779 case 0x80: case 0x81: case 0x82: case 0x83:
7780 if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 6
7781 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00007782 return True;
7783 break;
7784
7785 case 0xFE: case 0xFF:
sewardje9d8a262009-07-01 08:06:34 +00007786 if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 1
7787 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00007788 return True;
7789 break;
7790
7791 case 0xF6: case 0xF7:
sewardje9d8a262009-07-01 08:06:34 +00007792 if (gregOfRM(opc[1]) >= 2 && gregOfRM(opc[1]) <= 3
7793 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00007794 return True;
7795 break;
7796
7797 case 0x86: case 0x87:
sewardje9d8a262009-07-01 08:06:34 +00007798 if (!epartIsReg(opc[1]))
7799 return True;
7800 break;
sewardjc4356f02007-11-09 21:15:04 +00007801
7802 case 0x0F: {
7803 switch (opc[1]) {
7804 case 0xBB: case 0xB3: case 0xAB:
sewardje9d8a262009-07-01 08:06:34 +00007805 if (!epartIsReg(opc[2]))
7806 return True;
7807 break;
sewardjc4356f02007-11-09 21:15:04 +00007808 case 0xBA:
sewardje9d8a262009-07-01 08:06:34 +00007809 if (gregOfRM(opc[2]) >= 5 && gregOfRM(opc[2]) <= 7
7810 && !epartIsReg(opc[2]))
sewardjc4356f02007-11-09 21:15:04 +00007811 return True;
7812 break;
7813 case 0xB0: case 0xB1:
sewardje9d8a262009-07-01 08:06:34 +00007814 if (!epartIsReg(opc[2]))
7815 return True;
7816 break;
sewardjc4356f02007-11-09 21:15:04 +00007817 case 0xC7:
sewardje9d8a262009-07-01 08:06:34 +00007818 if (gregOfRM(opc[2]) == 1 && !epartIsReg(opc[2]) )
sewardjc4356f02007-11-09 21:15:04 +00007819 return True;
7820 break;
7821 case 0xC0: case 0xC1:
sewardje9d8a262009-07-01 08:06:34 +00007822 if (!epartIsReg(opc[2]))
7823 return True;
7824 break;
sewardjc4356f02007-11-09 21:15:04 +00007825 default:
7826 break;
7827 } /* switch (opc[1]) */
7828 break;
7829 }
7830
7831 default:
7832 break;
7833 } /* switch (opc[0]) */
7834
7835 return False;
7836}
7837
7838
sewardjc9a65702004-07-07 16:32:57 +00007839/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +00007840/*--- Disassemble a single instruction ---*/
sewardjc9a65702004-07-07 16:32:57 +00007841/*------------------------------------------------------------*/
7842
sewardje9d8a262009-07-01 08:06:34 +00007843/* Disassemble a single instruction into IR. The instruction is
7844 located in host memory at &guest_code[delta]. *expect_CAS is set
7845 to True if the resulting IR is expected to contain an IRCAS
7846 statement, and False if it's not expected to. This makes it
7847 possible for the caller of disInstr_X86_WRK to check that
7848 LOCK-prefixed instructions are at least plausibly translated, in
7849 that it becomes possible to check that a (validly) LOCK-prefixed
7850 instruction generates a translation containing an IRCAS, and
7851 instructions without LOCK prefixes don't generate translations
7852 containing an IRCAS.
7853*/
sewardj9e6491a2005-07-02 19:24:10 +00007854static
sewardje9d8a262009-07-01 08:06:34 +00007855DisResult disInstr_X86_WRK (
7856 /*OUT*/Bool* expect_CAS,
sewardj9e6491a2005-07-02 19:24:10 +00007857 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +00007858 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +00007859 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +00007860 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +00007861 Long delta64,
sewardj02834302010-07-29 18:10:51 +00007862 VexArchInfo* archinfo,
7863 VexAbiInfo* vbi
sewardj9e6491a2005-07-02 19:24:10 +00007864 )
sewardjc9a65702004-07-07 16:32:57 +00007865{
sewardjce70a5c2004-10-18 14:09:54 +00007866 IRType ty;
sewardjb5452082004-12-04 20:33:02 +00007867 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjce70a5c2004-10-18 14:09:54 +00007868 Int alen;
sewardjc4356f02007-11-09 21:15:04 +00007869 UChar opc, modrm, abyte, pre;
sewardjce70a5c2004-10-18 14:09:54 +00007870 UInt d32;
sewardjc9a43662004-11-30 18:51:59 +00007871 HChar dis_buf[50];
sewardjc4356f02007-11-09 21:15:04 +00007872 Int am_sz, d_sz, n_prefixes;
sewardj9e6491a2005-07-02 19:24:10 +00007873 DisResult dres;
sewardjc9a43662004-11-30 18:51:59 +00007874 UChar* insn; /* used in SSE decoders */
sewardjce70a5c2004-10-18 14:09:54 +00007875
sewardj9e6491a2005-07-02 19:24:10 +00007876 /* The running delta */
7877 Int delta = (Int)delta64;
7878
sewardjc9a65702004-07-07 16:32:57 +00007879 /* Holds eip at the start of the insn, so that we can print
7880 consistent error messages for unimplemented insns. */
sewardj9e6491a2005-07-02 19:24:10 +00007881 Int delta_start = delta;
sewardjc9a65702004-07-07 16:32:57 +00007882
7883 /* sz denotes the nominal data-op size of the insn; we change it to
7884 2 if an 0x66 prefix is seen */
7885 Int sz = 4;
7886
7887 /* sorb holds the segment-override-prefix byte, if any. Zero if no
7888 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
7889 indicating the prefix. */
7890 UChar sorb = 0;
7891
sewardjc4356f02007-11-09 21:15:04 +00007892 /* Gets set to True if a LOCK prefix is seen. */
7893 Bool pfx_lock = False;
7894
sewardj9e6491a2005-07-02 19:24:10 +00007895 /* Set result defaults. */
7896 dres.whatNext = Dis_Continue;
7897 dres.len = 0;
7898 dres.continueAt = 0;
sewardjce70a5c2004-10-18 14:09:54 +00007899
sewardje9d8a262009-07-01 08:06:34 +00007900 *expect_CAS = False;
7901
sewardjb5452082004-12-04 20:33:02 +00007902 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjc9a65702004-07-07 16:32:57 +00007903
sewardje9d8a262009-07-01 08:06:34 +00007904 vassert(guest_EIP_bbstart + delta == guest_EIP_curr_instr);
sewardj9e6491a2005-07-02 19:24:10 +00007905 DIP("\t0x%x: ", guest_EIP_bbstart+delta);
7906
7907 /* We may be asked to update the guest EIP before going further. */
7908 if (put_IP)
7909 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr)) );
sewardjc9a65702004-07-07 16:32:57 +00007910
sewardjce02aa72006-01-12 12:27:58 +00007911 /* Spot "Special" instructions (see comment at top of file). */
sewardj750f4072004-07-26 22:39:11 +00007912 {
7913 UChar* code = (UChar*)(guest_code + delta);
sewardjce02aa72006-01-12 12:27:58 +00007914 /* Spot the 12-byte preamble:
7915 C1C703 roll $3, %edi
7916 C1C70D roll $13, %edi
7917 C1C71D roll $29, %edi
7918 C1C713 roll $19, %edi
sewardj750f4072004-07-26 22:39:11 +00007919 */
sewardjce02aa72006-01-12 12:27:58 +00007920 if (code[ 0] == 0xC1 && code[ 1] == 0xC7 && code[ 2] == 0x03 &&
7921 code[ 3] == 0xC1 && code[ 4] == 0xC7 && code[ 5] == 0x0D &&
7922 code[ 6] == 0xC1 && code[ 7] == 0xC7 && code[ 8] == 0x1D &&
7923 code[ 9] == 0xC1 && code[10] == 0xC7 && code[11] == 0x13) {
7924 /* Got a "Special" instruction preamble. Which one is it? */
7925 if (code[12] == 0x87 && code[13] == 0xDB /* xchgl %ebx,%ebx */) {
7926 /* %EDX = client_request ( %EAX ) */
7927 DIP("%%edx = client_request ( %%eax )\n");
7928 delta += 14;
7929 jmp_lit(Ijk_ClientReq, guest_EIP_bbstart+delta);
7930 dres.whatNext = Dis_StopHere;
7931 goto decode_success;
7932 }
7933 else
7934 if (code[12] == 0x87 && code[13] == 0xC9 /* xchgl %ecx,%ecx */) {
7935 /* %EAX = guest_NRADDR */
7936 DIP("%%eax = guest_NRADDR\n");
7937 delta += 14;
7938 putIReg(4, R_EAX, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
7939 goto decode_success;
7940 }
7941 else
7942 if (code[12] == 0x87 && code[13] == 0xD2 /* xchgl %edx,%edx */) {
7943 /* call-noredir *%EAX */
7944 DIP("call-noredir *%%eax\n");
7945 delta += 14;
7946 t1 = newTemp(Ity_I32);
7947 assign(t1, getIReg(4,R_EAX));
7948 t2 = newTemp(Ity_I32);
7949 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
7950 putIReg(4, R_ESP, mkexpr(t2));
7951 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta));
7952 jmp_treg(Ijk_NoRedir,t1);
7953 dres.whatNext = Dis_StopHere;
7954 goto decode_success;
7955 }
7956 /* We don't know what it is. */
7957 goto decode_failure;
7958 /*NOTREACHED*/
sewardj750f4072004-07-26 22:39:11 +00007959 }
7960 }
sewardjc9a65702004-07-07 16:32:57 +00007961
sewardjc4356f02007-11-09 21:15:04 +00007962 /* Handle a couple of weird-ass NOPs that have been observed in the
7963 wild. */
7964 {
sewardjbb3f52d2005-01-07 14:14:50 +00007965 UChar* code = (UChar*)(guest_code + delta);
sewardjc4356f02007-11-09 21:15:04 +00007966 /* Sun's JVM 1.5.0 uses the following as a NOP:
7967 26 2E 64 65 90 %es:%cs:%fs:%gs:nop */
7968 if (code[0] == 0x26 && code[1] == 0x2E && code[2] == 0x64
7969 && code[3] == 0x65 && code[4] == 0x90) {
7970 DIP("%%es:%%cs:%%fs:%%gs:nop\n");
7971 delta += 5;
7972 goto decode_success;
sewardjbb3f52d2005-01-07 14:14:50 +00007973 }
sewardjdeceef82010-05-03 21:58:22 +00007974 /* Don't barf on recent binutils padding,
7975 all variants of which are: nopw %cs:0x0(%eax,%eax,1)
7976 66 2e 0f 1f 84 00 00 00 00 00
7977 66 66 2e 0f 1f 84 00 00 00 00 00
7978 66 66 66 2e 0f 1f 84 00 00 00 00 00
7979 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
7980 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
7981 66 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
7982 */
7983 if (code[0] == 0x66) {
7984 Int data16_cnt;
7985 for (data16_cnt = 1; data16_cnt < 6; data16_cnt++)
7986 if (code[data16_cnt] != 0x66)
7987 break;
7988 if (code[data16_cnt] == 0x2E && code[data16_cnt + 1] == 0x0F
7989 && code[data16_cnt + 2] == 0x1F && code[data16_cnt + 3] == 0x84
7990 && code[data16_cnt + 4] == 0x00 && code[data16_cnt + 5] == 0x00
7991 && code[data16_cnt + 6] == 0x00 && code[data16_cnt + 7] == 0x00
7992 && code[data16_cnt + 8] == 0x00 ) {
7993 DIP("nopw %%cs:0x0(%%eax,%%eax,1)\n");
7994 delta += 9 + data16_cnt;
7995 goto decode_success;
7996 }
sewardjce4a2822005-01-07 13:25:28 +00007997 }
sewardjc4356f02007-11-09 21:15:04 +00007998 }
sewardjbb3f52d2005-01-07 14:14:50 +00007999
sewardjc4356f02007-11-09 21:15:04 +00008000 /* Normal instruction handling starts here. */
sewardjc9a65702004-07-07 16:32:57 +00008001
sewardjc4356f02007-11-09 21:15:04 +00008002 /* Deal with some but not all prefixes:
8003 66(oso)
8004 F0(lock)
8005 2E(cs:) 3E(ds:) 26(es:) 64(fs:) 65(gs:) 36(ss:)
8006 Not dealt with (left in place):
8007 F2 F3
8008 */
8009 n_prefixes = 0;
8010 while (True) {
8011 if (n_prefixes > 7) goto decode_failure;
8012 pre = getUChar(delta);
8013 switch (pre) {
8014 case 0x66:
8015 sz = 2;
8016 break;
8017 case 0xF0:
8018 pfx_lock = True;
sewardje9d8a262009-07-01 08:06:34 +00008019 *expect_CAS = True;
sewardjc4356f02007-11-09 21:15:04 +00008020 break;
8021 case 0x3E: /* %DS: */
8022 case 0x26: /* %ES: */
8023 case 0x64: /* %FS: */
8024 case 0x65: /* %GS: */
8025 if (sorb != 0)
8026 goto decode_failure; /* only one seg override allowed */
8027 sorb = pre;
8028 break;
8029 case 0x2E: { /* %CS: */
8030 /* 2E prefix on a conditional branch instruction is a
8031 branch-prediction hint, which can safely be ignored. */
sewardjc9a65702004-07-07 16:32:57 +00008032 UChar op1 = getIByte(delta+1);
8033 UChar op2 = getIByte(delta+2);
8034 if ((op1 >= 0x70 && op1 <= 0x7F)
8035 || (op1 == 0xE3)
8036 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
sewardj4dfb1992005-03-13 18:56:28 +00008037 if (0) vex_printf("vex x86->IR: ignoring branch hint\n");
sewardjc4356f02007-11-09 21:15:04 +00008038 } else {
8039 /* All other CS override cases are not handled */
8040 goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +00008041 }
sewardjc4356f02007-11-09 21:15:04 +00008042 break;
sewardjc9a65702004-07-07 16:32:57 +00008043 }
sewardjc4356f02007-11-09 21:15:04 +00008044 case 0x36: /* %SS: */
8045 /* SS override cases are not handled */
8046 goto decode_failure;
8047 default:
8048 goto not_a_prefix;
8049 }
8050 n_prefixes++;
8051 delta++;
sewardjc9a65702004-07-07 16:32:57 +00008052 }
8053
sewardjc4356f02007-11-09 21:15:04 +00008054 not_a_prefix:
8055
8056 /* Now we should be looking at the primary opcode byte or the
8057 leading F2 or F3. Check that any LOCK prefix is actually
8058 allowed. */
8059
sewardjc4356f02007-11-09 21:15:04 +00008060 if (pfx_lock) {
8061 if (can_be_used_with_LOCK_prefix( (UChar*)&guest_code[delta] )) {
sewardjc4356f02007-11-09 21:15:04 +00008062 DIP("lock ");
8063 } else {
sewardje9d8a262009-07-01 08:06:34 +00008064 *expect_CAS = False;
sewardjc4356f02007-11-09 21:15:04 +00008065 goto decode_failure;
8066 }
8067 }
8068
8069
sewardjc9a43662004-11-30 18:51:59 +00008070 /* ---------------------------------------------------- */
8071 /* --- The SSE decoder. --- */
8072 /* ---------------------------------------------------- */
8073
sewardj4cb918d2004-12-03 19:43:31 +00008074 /* What did I do to deserve SSE ? Perhaps I was really bad in a
8075 previous life? */
8076
sewardj9df271d2004-12-31 22:37:42 +00008077 /* Note, this doesn't handle SSE2 or SSE3. That is handled in a
8078 later section, further on. */
8079
sewardja0e83b02005-01-06 12:36:38 +00008080 insn = (UChar*)&guest_code[delta];
8081
8082 /* Treat fxsave specially. It should be doable even on an SSE0
8083 (Pentium-II class) CPU. Hence be prepared to handle it on
8084 any subarchitecture variant.
8085 */
8086
8087 /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
8088 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8089 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj9a036bf2005-03-14 18:19:08 +00008090 IRDirty* d;
sewardja0e83b02005-01-06 12:36:38 +00008091 modrm = getIByte(delta+2);
8092 vassert(sz == 4);
8093 vassert(!epartIsReg(modrm));
8094
8095 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8096 delta += 2+alen;
sewardjec993de2011-01-21 18:02:54 +00008097 gen_SEGV_if_not_16_aligned(addr);
sewardja0e83b02005-01-06 12:36:38 +00008098
sewardj33dd31b2005-01-08 18:17:32 +00008099 DIP("fxsave %s\n", dis_buf);
sewardja0e83b02005-01-06 12:36:38 +00008100
8101 /* Uses dirty helper:
8102 void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
sewardj9a036bf2005-03-14 18:19:08 +00008103 d = unsafeIRDirty_0_N (
8104 0/*regparms*/,
8105 "x86g_dirtyhelper_FXSAVE",
8106 &x86g_dirtyhelper_FXSAVE,
8107 mkIRExprVec_1( mkexpr(addr) )
8108 );
sewardja0e83b02005-01-06 12:36:38 +00008109 d->needsBBP = True;
8110
8111 /* declare we're writing memory */
8112 d->mFx = Ifx_Write;
8113 d->mAddr = mkexpr(addr);
8114 d->mSize = 512;
8115
8116 /* declare we're reading guest state */
8117 d->nFxState = 7;
8118
8119 d->fxState[0].fx = Ifx_Read;
8120 d->fxState[0].offset = OFFB_FTOP;
8121 d->fxState[0].size = sizeof(UInt);
8122
8123 d->fxState[1].fx = Ifx_Read;
8124 d->fxState[1].offset = OFFB_FPREGS;
8125 d->fxState[1].size = 8 * sizeof(ULong);
8126
8127 d->fxState[2].fx = Ifx_Read;
8128 d->fxState[2].offset = OFFB_FPTAGS;
8129 d->fxState[2].size = 8 * sizeof(UChar);
8130
8131 d->fxState[3].fx = Ifx_Read;
8132 d->fxState[3].offset = OFFB_FPROUND;
8133 d->fxState[3].size = sizeof(UInt);
8134
8135 d->fxState[4].fx = Ifx_Read;
8136 d->fxState[4].offset = OFFB_FC3210;
8137 d->fxState[4].size = sizeof(UInt);
8138
8139 d->fxState[5].fx = Ifx_Read;
8140 d->fxState[5].offset = OFFB_XMM0;
8141 d->fxState[5].size = 8 * sizeof(U128);
8142
8143 d->fxState[6].fx = Ifx_Read;
8144 d->fxState[6].offset = OFFB_SSEROUND;
8145 d->fxState[6].size = sizeof(UInt);
8146
8147 /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8148 images are packed back-to-back. If not, the value of
8149 d->fxState[5].size is wrong. */
8150 vassert(16 == sizeof(U128));
8151 vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8152
8153 stmt( IRStmt_Dirty(d) );
8154
8155 goto decode_success;
8156 }
8157
sewardj3800e2d2008-05-09 13:24:43 +00008158 /* 0F AE /1 = FXRSTOR m512 -- read x87 and SSE state from memory */
8159 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8160 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 1) {
8161 IRDirty* d;
8162 modrm = getIByte(delta+2);
8163 vassert(sz == 4);
8164 vassert(!epartIsReg(modrm));
8165
8166 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8167 delta += 2+alen;
sewardjec993de2011-01-21 18:02:54 +00008168 gen_SEGV_if_not_16_aligned(addr);
sewardj3800e2d2008-05-09 13:24:43 +00008169
8170 DIP("fxrstor %s\n", dis_buf);
8171
8172 /* Uses dirty helper:
sewardjec993de2011-01-21 18:02:54 +00008173 VexEmWarn x86g_do_FXRSTOR ( VexGuestX86State*, UInt )
8174 NOTE:
8175 the VexEmWarn value is simply ignored (unlike for FRSTOR)
8176 */
sewardj3800e2d2008-05-09 13:24:43 +00008177 d = unsafeIRDirty_0_N (
8178 0/*regparms*/,
8179 "x86g_dirtyhelper_FXRSTOR",
8180 &x86g_dirtyhelper_FXRSTOR,
8181 mkIRExprVec_1( mkexpr(addr) )
8182 );
8183 d->needsBBP = True;
8184
8185 /* declare we're reading memory */
8186 d->mFx = Ifx_Read;
8187 d->mAddr = mkexpr(addr);
8188 d->mSize = 512;
8189
8190 /* declare we're writing guest state */
8191 d->nFxState = 7;
8192
8193 d->fxState[0].fx = Ifx_Write;
8194 d->fxState[0].offset = OFFB_FTOP;
8195 d->fxState[0].size = sizeof(UInt);
8196
8197 d->fxState[1].fx = Ifx_Write;
8198 d->fxState[1].offset = OFFB_FPREGS;
8199 d->fxState[1].size = 8 * sizeof(ULong);
8200
8201 d->fxState[2].fx = Ifx_Write;
8202 d->fxState[2].offset = OFFB_FPTAGS;
8203 d->fxState[2].size = 8 * sizeof(UChar);
8204
8205 d->fxState[3].fx = Ifx_Write;
8206 d->fxState[3].offset = OFFB_FPROUND;
8207 d->fxState[3].size = sizeof(UInt);
8208
8209 d->fxState[4].fx = Ifx_Write;
8210 d->fxState[4].offset = OFFB_FC3210;
8211 d->fxState[4].size = sizeof(UInt);
8212
8213 d->fxState[5].fx = Ifx_Write;
8214 d->fxState[5].offset = OFFB_XMM0;
8215 d->fxState[5].size = 8 * sizeof(U128);
8216
8217 d->fxState[6].fx = Ifx_Write;
8218 d->fxState[6].offset = OFFB_SSEROUND;
8219 d->fxState[6].size = sizeof(UInt);
8220
8221 /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8222 images are packed back-to-back. If not, the value of
8223 d->fxState[5].size is wrong. */
8224 vassert(16 == sizeof(U128));
8225 vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8226
8227 stmt( IRStmt_Dirty(d) );
8228
8229 goto decode_success;
8230 }
8231
sewardja0e83b02005-01-06 12:36:38 +00008232 /* ------ SSE decoder main ------ */
8233
sewardj9df271d2004-12-31 22:37:42 +00008234 /* Skip parts of the decoder which don't apply given the stated
8235 guest subarchitecture. */
sewardj5117ce12006-01-27 21:20:15 +00008236 if (archinfo->hwcaps == 0/*baseline, no sse at all*/)
sewardj9df271d2004-12-31 22:37:42 +00008237 goto after_sse_decoders;
8238
8239 /* Otherwise we must be doing sse1 or sse2, so we can at least try
8240 for SSE1 here. */
sewardjc9a43662004-11-30 18:51:59 +00008241
sewardjc9a43662004-11-30 18:51:59 +00008242 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00008243 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj129b3d92004-12-05 15:42:05 +00008244 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
sewardjc9a43662004-11-30 18:51:59 +00008245 goto decode_success;
8246 }
8247
sewardj1e6ad742004-12-02 16:16:11 +00008248 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
8249 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
8250 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008251 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
sewardj1e6ad742004-12-02 16:16:11 +00008252 goto decode_success;
8253 }
8254
8255 /* 0F 55 = ANDNPS -- G = (not G) and E */
sewardj636ad762004-12-07 11:16:04 +00008256 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00008257 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00008258 goto decode_success;
8259 }
8260
8261 /* 0F 54 = ANDPS -- G = G and E */
sewardj636ad762004-12-07 11:16:04 +00008262 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00008263 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00008264 goto decode_success;
8265 }
8266
8267 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00008268 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj1e6ad742004-12-02 16:16:11 +00008269 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
8270 goto decode_success;
8271 }
8272
8273 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
8274 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
8275 vassert(sz == 4);
8276 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
8277 goto decode_success;
8278 }
sewardjc9a43662004-11-30 18:51:59 +00008279
sewardjfd226452004-12-07 19:02:18 +00008280 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjc1e7dfc2004-12-05 19:29:45 +00008281 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjfd226452004-12-07 19:02:18 +00008282 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
sewardj67e002d2004-12-02 18:16:33 +00008283 IRTemp argL = newTemp(Ity_F32);
8284 IRTemp argR = newTemp(Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +00008285 modrm = getIByte(delta+2);
8286 if (epartIsReg(modrm)) {
8287 assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
8288 delta += 2+1;
sewardjc1e7dfc2004-12-05 19:29:45 +00008289 DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8290 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00008291 } else {
8292 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8293 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
8294 delta += 2+alen;
sewardjc1e7dfc2004-12-05 19:29:45 +00008295 DIP("[u]comiss %s,%s\n", dis_buf,
8296 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00008297 }
8298 assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
8299
8300 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
8301 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
8302 stmt( IRStmt_Put(
8303 OFFB_CC_DEP1,
8304 binop( Iop_And32,
8305 binop(Iop_CmpF64,
8306 unop(Iop_F32toF64,mkexpr(argL)),
8307 unop(Iop_F32toF64,mkexpr(argR))),
8308 mkU32(0x45)
8309 )));
sewardja3b7e3a2005-04-05 01:54:19 +00008310 /* Set NDEP even though it isn't used. This makes redundant-PUT
8311 elimination of previous stores to this field work better. */
8312 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj67e002d2004-12-02 18:16:33 +00008313 goto decode_success;
8314 }
sewardjc9a43662004-11-30 18:51:59 +00008315
sewardj4cb918d2004-12-03 19:43:31 +00008316 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
8317 half xmm */
sewardjfd226452004-12-07 19:02:18 +00008318 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj4cb918d2004-12-03 19:43:31 +00008319 IRTemp arg64 = newTemp(Ity_I64);
8320 IRTemp rmode = newTemp(Ity_I32);
8321 vassert(sz == 4);
8322
8323 modrm = getIByte(delta+2);
8324 do_MMX_preamble();
8325 if (epartIsReg(modrm)) {
8326 assign( arg64, getMMXReg(eregOfRM(modrm)) );
8327 delta += 2+1;
8328 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8329 nameXMMReg(gregOfRM(modrm)));
8330 } else {
8331 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8332 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8333 delta += 2+alen;
8334 DIP("cvtpi2ps %s,%s\n", dis_buf,
8335 nameXMMReg(gregOfRM(modrm)) );
8336 }
8337
8338 assign( rmode, get_sse_roundingmode() );
8339
8340 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00008341 gregOfRM(modrm), 0,
8342 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00008343 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00008344 unop(Iop_I32StoF64,
sewardj3bca9062004-12-04 14:36:09 +00008345 unop(Iop_64to32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00008346
8347 putXMMRegLane32F(
8348 gregOfRM(modrm), 1,
sewardj3bca9062004-12-04 14:36:09 +00008349 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00008350 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00008351 unop(Iop_I32StoF64,
sewardj3bca9062004-12-04 14:36:09 +00008352 unop(Iop_64HIto32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00008353
8354 goto decode_success;
8355 }
8356
8357 /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
8358 quarter xmm */
8359 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
8360 IRTemp arg32 = newTemp(Ity_I32);
8361 IRTemp rmode = newTemp(Ity_I32);
8362 vassert(sz == 4);
8363
8364 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00008365 if (epartIsReg(modrm)) {
8366 assign( arg32, getIReg(4, eregOfRM(modrm)) );
8367 delta += 3+1;
8368 DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
8369 nameXMMReg(gregOfRM(modrm)));
8370 } else {
8371 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8372 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8373 delta += 3+alen;
8374 DIP("cvtsi2ss %s,%s\n", dis_buf,
8375 nameXMMReg(gregOfRM(modrm)) );
8376 }
8377
8378 assign( rmode, get_sse_roundingmode() );
8379
8380 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00008381 gregOfRM(modrm), 0,
8382 binop(Iop_F64toF32,
8383 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00008384 unop(Iop_I32StoF64, mkexpr(arg32)) ) );
sewardj4cb918d2004-12-03 19:43:31 +00008385
8386 goto decode_success;
8387 }
8388
8389 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8390 I32 in mmx, according to prevailing SSE rounding mode */
8391 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8392 I32 in mmx, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00008393 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj4cb918d2004-12-03 19:43:31 +00008394 IRTemp dst64 = newTemp(Ity_I64);
8395 IRTemp rmode = newTemp(Ity_I32);
8396 IRTemp f32lo = newTemp(Ity_F32);
8397 IRTemp f32hi = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00008398 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00008399
8400 do_MMX_preamble();
8401 modrm = getIByte(delta+2);
8402
8403 if (epartIsReg(modrm)) {
8404 delta += 2+1;
8405 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8406 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
8407 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8408 nameXMMReg(eregOfRM(modrm)),
8409 nameMMXReg(gregOfRM(modrm)));
8410 } else {
8411 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8412 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8413 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
8414 mkexpr(addr),
8415 mkU32(4) )));
8416 delta += 2+alen;
8417 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8418 dis_buf,
8419 nameMMXReg(gregOfRM(modrm)));
8420 }
8421
8422 if (r2zero) {
8423 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8424 } else {
8425 assign( rmode, get_sse_roundingmode() );
8426 }
8427
8428 assign(
8429 dst64,
8430 binop( Iop_32HLto64,
sewardj6c299f32009-12-31 18:00:12 +00008431 binop( Iop_F64toI32S,
sewardj4cb918d2004-12-03 19:43:31 +00008432 mkexpr(rmode),
8433 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
sewardj6c299f32009-12-31 18:00:12 +00008434 binop( Iop_F64toI32S,
sewardj4cb918d2004-12-03 19:43:31 +00008435 mkexpr(rmode),
8436 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8437 )
8438 );
8439
8440 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
8441 goto decode_success;
8442 }
8443
8444 /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
8445 I32 in ireg, according to prevailing SSE rounding mode */
8446 /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
sewardj0b210442005-02-23 13:28:27 +00008447 I32 in ireg, rounding towards zero */
sewardj4cb918d2004-12-03 19:43:31 +00008448 if (insn[0] == 0xF3 && insn[1] == 0x0F
8449 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
8450 IRTemp rmode = newTemp(Ity_I32);
8451 IRTemp f32lo = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00008452 Bool r2zero = toBool(insn[2] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00008453 vassert(sz == 4);
8454
sewardj4cb918d2004-12-03 19:43:31 +00008455 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00008456 if (epartIsReg(modrm)) {
8457 delta += 3+1;
8458 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8459 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8460 nameXMMReg(eregOfRM(modrm)),
8461 nameIReg(4, gregOfRM(modrm)));
8462 } else {
8463 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8464 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8465 delta += 3+alen;
8466 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8467 dis_buf,
8468 nameIReg(4, gregOfRM(modrm)));
8469 }
8470
8471 if (r2zero) {
sewardj7df596b2004-12-06 14:29:12 +00008472 assign( rmode, mkU32((UInt)Irrm_ZERO) );
sewardj4cb918d2004-12-03 19:43:31 +00008473 } else {
8474 assign( rmode, get_sse_roundingmode() );
8475 }
8476
8477 putIReg(4, gregOfRM(modrm),
sewardj6c299f32009-12-31 18:00:12 +00008478 binop( Iop_F64toI32S,
sewardj4cb918d2004-12-03 19:43:31 +00008479 mkexpr(rmode),
8480 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8481 );
8482
8483 goto decode_success;
8484 }
8485
sewardj176a59c2004-12-03 20:08:31 +00008486 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
sewardjfd226452004-12-07 19:02:18 +00008487 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj129b3d92004-12-05 15:42:05 +00008488 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00008489 goto decode_success;
8490 }
8491
8492 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8493 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
8494 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008495 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00008496 goto decode_success;
8497 }
8498
sewardj7df596b2004-12-06 14:29:12 +00008499 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
8500 if (insn[0] == 0x0F && insn[1] == 0xAE
8501 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
8502
8503 IRTemp t64 = newTemp(Ity_I64);
8504 IRTemp ew = newTemp(Ity_I32);
8505
8506 modrm = getIByte(delta+2);
8507 vassert(!epartIsReg(modrm));
8508 vassert(sz == 4);
8509
8510 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8511 delta += 2+alen;
sewardj33dd31b2005-01-08 18:17:32 +00008512 DIP("ldmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00008513
8514 /* The only thing we observe in %mxcsr is the rounding mode.
8515 Therefore, pass the 32-bit value (SSE native-format control
8516 word) to a clean helper, getting back a 64-bit value, the
8517 lower half of which is the SSEROUND value to store, and the
8518 upper half of which is the emulation-warning token which may
8519 be generated.
8520 */
8521 /* ULong x86h_check_ldmxcsr ( UInt ); */
8522 assign( t64, mkIRExprCCall(
8523 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00008524 "x86g_check_ldmxcsr",
8525 &x86g_check_ldmxcsr,
sewardj7df596b2004-12-06 14:29:12 +00008526 mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
8527 )
8528 );
8529
sewardj636ad762004-12-07 11:16:04 +00008530 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
sewardj7df596b2004-12-06 14:29:12 +00008531 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
8532 put_emwarn( mkexpr(ew) );
8533 /* Finally, if an emulation warning was reported, side-exit to
8534 the next insn, reporting the warning, so that Valgrind's
8535 dispatcher sees the warning. */
8536 stmt(
8537 IRStmt_Exit(
8538 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
8539 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00008540 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj7df596b2004-12-06 14:29:12 +00008541 )
8542 );
8543 goto decode_success;
8544 }
8545
sewardjd71ba832006-12-27 01:15:29 +00008546 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8547 /* 0F F7 = MASKMOVQ -- 8x8 masked store */
8548 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF7) {
8549 Bool ok = False;
8550 delta = dis_MMX( &ok, sorb, sz, delta+1 );
8551 if (!ok)
8552 goto decode_failure;
8553 goto decode_success;
8554 }
8555
sewardj176a59c2004-12-03 20:08:31 +00008556 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00008557 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj129b3d92004-12-05 15:42:05 +00008558 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00008559 goto decode_success;
8560 }
8561
8562 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
8563 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
8564 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008565 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00008566 goto decode_success;
8567 }
8568
8569 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00008570 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj129b3d92004-12-05 15:42:05 +00008571 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00008572 goto decode_success;
8573 }
8574
8575 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
8576 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
8577 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008578 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00008579 goto decode_success;
8580 }
sewardj4cb918d2004-12-03 19:43:31 +00008581
sewardj9636b442004-12-04 01:38:37 +00008582 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
sewardjc2feffc2004-12-08 12:31:22 +00008583 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
8584 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
sewardj9636b442004-12-04 01:38:37 +00008585 modrm = getIByte(delta+2);
sewardj9636b442004-12-04 01:38:37 +00008586 if (epartIsReg(modrm)) {
8587 putXMMReg( gregOfRM(modrm),
8588 getXMMReg( eregOfRM(modrm) ));
8589 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8590 nameXMMReg(gregOfRM(modrm)));
8591 delta += 2+1;
8592 } else {
8593 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +00008594 if (insn[1] == 0x28/*movaps*/)
8595 gen_SEGV_if_not_16_aligned( addr );
sewardj9636b442004-12-04 01:38:37 +00008596 putXMMReg( gregOfRM(modrm),
8597 loadLE(Ity_V128, mkexpr(addr)) );
8598 DIP("mov[ua]ps %s,%s\n", dis_buf,
8599 nameXMMReg(gregOfRM(modrm)));
8600 delta += 2+alen;
8601 }
8602 goto decode_success;
8603 }
8604
sewardj09f41552004-12-15 12:35:00 +00008605 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
sewardj3ed54842005-08-25 21:34:24 +00008606 /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
8607 if (sz == 4 && insn[0] == 0x0F
8608 && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj09f41552004-12-15 12:35:00 +00008609 modrm = getIByte(delta+2);
sewardj09f41552004-12-15 12:35:00 +00008610 if (epartIsReg(modrm)) {
8611 /* fall through; awaiting test case */
8612 } else {
8613 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +00008614 if (insn[1] == 0x29/*movaps*/)
8615 gen_SEGV_if_not_16_aligned( addr );
sewardj09f41552004-12-15 12:35:00 +00008616 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj3ed54842005-08-25 21:34:24 +00008617 DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRM(modrm)),
8618 dis_buf );
sewardj09f41552004-12-15 12:35:00 +00008619 delta += 2+alen;
8620 goto decode_success;
8621 }
8622 }
8623
sewardj0bd7ce62004-12-05 02:47:40 +00008624 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
8625 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00008626 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
sewardj0bd7ce62004-12-05 02:47:40 +00008627 modrm = getIByte(delta+2);
8628 if (epartIsReg(modrm)) {
8629 delta += 2+1;
8630 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
8631 getXMMRegLane64( eregOfRM(modrm), 0 ) );
8632 DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8633 nameXMMReg(gregOfRM(modrm)));
8634 } else {
8635 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8636 delta += 2+alen;
8637 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
8638 loadLE(Ity_I64, mkexpr(addr)) );
8639 DIP("movhps %s,%s\n", dis_buf,
sewardjc2feffc2004-12-08 12:31:22 +00008640 nameXMMReg( gregOfRM(modrm) ));
sewardj0bd7ce62004-12-05 02:47:40 +00008641 }
8642 goto decode_success;
8643 }
8644
8645 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00008646 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
sewardj0bd7ce62004-12-05 02:47:40 +00008647 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00008648 delta += 2;
8649 addr = disAMode ( &alen, sorb, delta, dis_buf );
8650 delta += alen;
8651 storeLE( mkexpr(addr),
8652 getXMMRegLane64( gregOfRM(insn[2]),
8653 1/*upper lane*/ ) );
8654 DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
8655 dis_buf);
8656 goto decode_success;
8657 }
8658 /* else fall through */
8659 }
8660
8661 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
8662 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00008663 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
sewardj0bd7ce62004-12-05 02:47:40 +00008664 modrm = getIByte(delta+2);
8665 if (epartIsReg(modrm)) {
8666 delta += 2+1;
8667 putXMMRegLane64( gregOfRM(modrm),
8668 0/*lower lane*/,
8669 getXMMRegLane64( eregOfRM(modrm), 1 ));
8670 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
8671 nameXMMReg(gregOfRM(modrm)));
8672 } else {
8673 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8674 delta += 2+alen;
8675 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
8676 loadLE(Ity_I64, mkexpr(addr)) );
8677 DIP("movlps %s, %s\n",
8678 dis_buf, nameXMMReg( gregOfRM(modrm) ));
8679 }
8680 goto decode_success;
8681 }
8682
8683 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00008684 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
sewardj0bd7ce62004-12-05 02:47:40 +00008685 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00008686 delta += 2;
8687 addr = disAMode ( &alen, sorb, delta, dis_buf );
8688 delta += alen;
8689 storeLE( mkexpr(addr),
8690 getXMMRegLane64( gregOfRM(insn[2]),
8691 0/*lower lane*/ ) );
8692 DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
8693 dis_buf);
8694 goto decode_success;
8695 }
8696 /* else fall through */
8697 }
8698
sewardj9636b442004-12-04 01:38:37 +00008699 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
8700 to 4 lowest bits of ireg(G) */
8701 if (insn[0] == 0x0F && insn[1] == 0x50) {
sewardj9636b442004-12-04 01:38:37 +00008702 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00008703 if (sz == 4 && epartIsReg(modrm)) {
8704 Int src;
8705 t0 = newTemp(Ity_I32);
8706 t1 = newTemp(Ity_I32);
8707 t2 = newTemp(Ity_I32);
8708 t3 = newTemp(Ity_I32);
sewardj129b3d92004-12-05 15:42:05 +00008709 delta += 2+1;
8710 src = eregOfRM(modrm);
8711 assign( t0, binop( Iop_And32,
8712 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
8713 mkU32(1) ));
8714 assign( t1, binop( Iop_And32,
8715 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
8716 mkU32(2) ));
8717 assign( t2, binop( Iop_And32,
8718 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
8719 mkU32(4) ));
8720 assign( t3, binop( Iop_And32,
8721 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
8722 mkU32(8) ));
8723 putIReg(4, gregOfRM(modrm),
8724 binop(Iop_Or32,
8725 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
8726 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
8727 )
8728 );
8729 DIP("movmskps %s,%s\n", nameXMMReg(src),
8730 nameIReg(4, gregOfRM(modrm)));
8731 goto decode_success;
8732 }
8733 /* else fall through */
sewardj9636b442004-12-04 01:38:37 +00008734 }
8735
8736 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj703d6d62005-05-11 02:55:00 +00008737 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardj9636b442004-12-04 01:38:37 +00008738 if (insn[0] == 0x0F && insn[1] == 0x2B) {
8739 modrm = getIByte(delta+2);
8740 if (!epartIsReg(modrm)) {
8741 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +00008742 gen_SEGV_if_not_16_aligned( addr );
sewardj9636b442004-12-04 01:38:37 +00008743 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj703d6d62005-05-11 02:55:00 +00008744 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
8745 dis_buf,
8746 nameXMMReg(gregOfRM(modrm)));
sewardj9636b442004-12-04 01:38:37 +00008747 delta += 2+alen;
8748 goto decode_success;
8749 }
8750 /* else fall through */
8751 }
8752
sewardjc2feffc2004-12-08 12:31:22 +00008753 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
sewardj9636b442004-12-04 01:38:37 +00008754 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
8755 Intel manual does not say anything about the usual business of
8756 the FP reg tags getting trashed whenever an MMX insn happens.
8757 So we just leave them alone.
8758 */
8759 if (insn[0] == 0x0F && insn[1] == 0xE7) {
8760 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00008761 if (sz == 4 && !epartIsReg(modrm)) {
sewardj519d66f2004-12-15 11:57:58 +00008762 /* do_MMX_preamble(); Intel docs don't specify this */
sewardj9636b442004-12-04 01:38:37 +00008763 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8764 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
8765 DIP("movntq %s,%s\n", dis_buf,
8766 nameMMXReg(gregOfRM(modrm)));
8767 delta += 2+alen;
8768 goto decode_success;
8769 }
8770 /* else fall through */
8771 }
8772
8773 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
8774 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
8775 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
8776 vassert(sz == 4);
8777 modrm = getIByte(delta+3);
8778 if (epartIsReg(modrm)) {
8779 putXMMRegLane32( gregOfRM(modrm), 0,
8780 getXMMRegLane32( eregOfRM(modrm), 0 ));
8781 DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8782 nameXMMReg(gregOfRM(modrm)));
8783 delta += 3+1;
8784 } else {
8785 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +00008786 /* zero bits 127:64 */
8787 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
8788 /* zero bits 63:32 */
8789 putXMMRegLane32( gregOfRM(modrm), 1, mkU32(0) );
8790 /* write bits 31:0 */
sewardj9636b442004-12-04 01:38:37 +00008791 putXMMRegLane32( gregOfRM(modrm), 0,
8792 loadLE(Ity_I32, mkexpr(addr)) );
8793 DIP("movss %s,%s\n", dis_buf,
8794 nameXMMReg(gregOfRM(modrm)));
8795 delta += 3+alen;
8796 }
8797 goto decode_success;
8798 }
8799
8800 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
8801 or lo 1/4 xmm). */
8802 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
8803 vassert(sz == 4);
8804 modrm = getIByte(delta+3);
8805 if (epartIsReg(modrm)) {
8806 /* fall through, we don't yet have a test case */
8807 } else {
8808 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8809 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +00008810 getXMMRegLane32(gregOfRM(modrm), 0) );
8811 DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardj9636b442004-12-04 01:38:37 +00008812 dis_buf);
8813 delta += 3+alen;
8814 goto decode_success;
8815 }
8816 }
8817
8818 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00008819 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj129b3d92004-12-05 15:42:05 +00008820 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
sewardj9636b442004-12-04 01:38:37 +00008821 goto decode_success;
8822 }
8823
8824 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
8825 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
8826 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008827 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
sewardj9636b442004-12-04 01:38:37 +00008828 goto decode_success;
8829 }
8830
8831 /* 0F 56 = ORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00008832 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +00008833 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_OrV128 );
sewardj9636b442004-12-04 01:38:37 +00008834 goto decode_success;
8835 }
8836
sewardj3bca9062004-12-04 14:36:09 +00008837 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8838 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00008839 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
sewardjb5452082004-12-04 20:33:02 +00008840 do_MMX_preamble();
8841 delta = dis_MMXop_regmem_to_reg (
8842 sorb, delta+2, insn[1], "pavgb", False );
8843 goto decode_success;
sewardj3bca9062004-12-04 14:36:09 +00008844 }
8845
sewardjb5452082004-12-04 20:33:02 +00008846 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8847 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00008848 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
sewardjb5452082004-12-04 20:33:02 +00008849 do_MMX_preamble();
8850 delta = dis_MMXop_regmem_to_reg (
8851 sorb, delta+2, insn[1], "pavgw", False );
8852 goto decode_success;
8853 }
8854
8855 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8856 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
8857 zero-extend of it in ireg(G). */
8858 if (insn[0] == 0x0F && insn[1] == 0xC5) {
8859 modrm = insn[2];
8860 if (sz == 4 && epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00008861 IRTemp sV = newTemp(Ity_I64);
8862 t5 = newTemp(Ity_I16);
sewardjb5452082004-12-04 20:33:02 +00008863 do_MMX_preamble();
sewardjb9fa69b2004-12-09 23:25:14 +00008864 assign(sV, getMMXReg(eregOfRM(modrm)));
8865 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00008866 switch (insn[3] & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00008867 case 0: assign(t5, mkexpr(t0)); break;
8868 case 1: assign(t5, mkexpr(t1)); break;
8869 case 2: assign(t5, mkexpr(t2)); break;
8870 case 3: assign(t5, mkexpr(t3)); break;
sewardjba89f4c2005-04-07 17:31:27 +00008871 default: vassert(0); /*NOTREACHED*/
sewardjb5452082004-12-04 20:33:02 +00008872 }
sewardjb9fa69b2004-12-09 23:25:14 +00008873 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
sewardjb5452082004-12-04 20:33:02 +00008874 DIP("pextrw $%d,%s,%s\n",
8875 (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
8876 nameIReg(4,gregOfRM(modrm)));
8877 delta += 4;
8878 goto decode_success;
8879 }
8880 /* else fall through */
8881 }
8882
8883 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8884 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
8885 put it into the specified lane of mmx(G). */
sewardje5854d62004-12-09 03:44:34 +00008886 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
8887 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
8888 mmx reg. t4 is the new lane value. t5 is the original
8889 mmx value. t6 is the new mmx value. */
8890 Int lane;
sewardje5854d62004-12-09 03:44:34 +00008891 t4 = newTemp(Ity_I16);
8892 t5 = newTemp(Ity_I64);
8893 t6 = newTemp(Ity_I64);
8894 modrm = insn[2];
8895 do_MMX_preamble();
sewardjb5452082004-12-04 20:33:02 +00008896
sewardje5854d62004-12-09 03:44:34 +00008897 assign(t5, getMMXReg(gregOfRM(modrm)));
sewardjb9fa69b2004-12-09 23:25:14 +00008898 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00008899
sewardje5854d62004-12-09 03:44:34 +00008900 if (epartIsReg(modrm)) {
8901 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +00008902 delta += 3+1;
8903 lane = insn[3+1-1];
sewardje5854d62004-12-09 03:44:34 +00008904 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8905 nameIReg(2,eregOfRM(modrm)),
8906 nameMMXReg(gregOfRM(modrm)));
8907 } else {
sewardj7420b092005-03-13 20:19:19 +00008908 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8909 delta += 3+alen;
8910 lane = insn[3+alen-1];
8911 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
8912 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8913 dis_buf,
8914 nameMMXReg(gregOfRM(modrm)));
sewardjb5452082004-12-04 20:33:02 +00008915 }
sewardje5854d62004-12-09 03:44:34 +00008916
8917 switch (lane & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00008918 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
8919 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
8920 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
8921 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
sewardjba89f4c2005-04-07 17:31:27 +00008922 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +00008923 }
8924 putMMXReg(gregOfRM(modrm), mkexpr(t6));
8925 goto decode_success;
sewardjb5452082004-12-04 20:33:02 +00008926 }
8927
8928 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8929 /* 0F EE = PMAXSW -- 16x4 signed max */
sewardje5854d62004-12-09 03:44:34 +00008930 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
sewardjb5452082004-12-04 20:33:02 +00008931 do_MMX_preamble();
8932 delta = dis_MMXop_regmem_to_reg (
8933 sorb, delta+2, insn[1], "pmaxsw", False );
8934 goto decode_success;
8935 }
8936
8937 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8938 /* 0F DE = PMAXUB -- 8x8 unsigned max */
sewardje5854d62004-12-09 03:44:34 +00008939 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
sewardjb5452082004-12-04 20:33:02 +00008940 do_MMX_preamble();
8941 delta = dis_MMXop_regmem_to_reg (
8942 sorb, delta+2, insn[1], "pmaxub", False );
8943 goto decode_success;
8944 }
8945
8946 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8947 /* 0F EA = PMINSW -- 16x4 signed min */
sewardje5854d62004-12-09 03:44:34 +00008948 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
sewardjb5452082004-12-04 20:33:02 +00008949 do_MMX_preamble();
8950 delta = dis_MMXop_regmem_to_reg (
8951 sorb, delta+2, insn[1], "pminsw", False );
8952 goto decode_success;
8953 }
8954
8955 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8956 /* 0F DA = PMINUB -- 8x8 unsigned min */
sewardje5854d62004-12-09 03:44:34 +00008957 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
sewardjb5452082004-12-04 20:33:02 +00008958 do_MMX_preamble();
8959 delta = dis_MMXop_regmem_to_reg (
8960 sorb, delta+2, insn[1], "pminub", False );
8961 goto decode_success;
8962 }
8963
8964 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8965 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
8966 mmx(G), turn them into a byte, and put zero-extend of it in
8967 ireg(G). */
sewardje5854d62004-12-09 03:44:34 +00008968 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
sewardjb5452082004-12-04 20:33:02 +00008969 modrm = insn[2];
sewardje5854d62004-12-09 03:44:34 +00008970 if (epartIsReg(modrm)) {
sewardjb5452082004-12-04 20:33:02 +00008971 do_MMX_preamble();
8972 t0 = newTemp(Ity_I64);
8973 t1 = newTemp(Ity_I32);
8974 assign(t0, getMMXReg(eregOfRM(modrm)));
8975 assign(t1, mkIRExprCCall(
8976 Ity_I32, 0/*regparms*/,
sewardj38a3f862005-01-13 15:06:51 +00008977 "x86g_calculate_mmx_pmovmskb",
8978 &x86g_calculate_mmx_pmovmskb,
sewardjb5452082004-12-04 20:33:02 +00008979 mkIRExprVec_1(mkexpr(t0))));
8980 putIReg(4, gregOfRM(modrm), mkexpr(t1));
8981 DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8982 nameIReg(4,gregOfRM(modrm)));
8983 delta += 3;
8984 goto decode_success;
8985 }
8986 /* else fall through */
8987 }
8988
sewardj0bd7ce62004-12-05 02:47:40 +00008989 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8990 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
sewardje5854d62004-12-09 03:44:34 +00008991 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
sewardj0bd7ce62004-12-05 02:47:40 +00008992 do_MMX_preamble();
8993 delta = dis_MMXop_regmem_to_reg (
8994 sorb, delta+2, insn[1], "pmuluh", False );
8995 goto decode_success;
8996 }
8997
sewardj7df596b2004-12-06 14:29:12 +00008998 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
8999 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
9000 /* 0F 18 /2 = PREFETCH1 */
9001 /* 0F 18 /3 = PREFETCH2 */
9002 if (insn[0] == 0x0F && insn[1] == 0x18
9003 && !epartIsReg(insn[2])
9004 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
9005 HChar* hintstr = "??";
9006
9007 modrm = getIByte(delta+2);
9008 vassert(!epartIsReg(modrm));
9009
9010 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9011 delta += 2+alen;
9012
9013 switch (gregOfRM(modrm)) {
9014 case 0: hintstr = "nta"; break;
9015 case 1: hintstr = "t0"; break;
9016 case 2: hintstr = "t1"; break;
9017 case 3: hintstr = "t2"; break;
sewardjba89f4c2005-04-07 17:31:27 +00009018 default: vassert(0); /*NOTREACHED*/
sewardj7df596b2004-12-06 14:29:12 +00009019 }
9020
9021 DIP("prefetch%s %s\n", hintstr, dis_buf);
9022 goto decode_success;
9023 }
9024
sewardj85317682006-03-06 14:07:58 +00009025 /* 0F 0D /0 = PREFETCH m8 -- 3DNow! prefetch */
9026 /* 0F 0D /1 = PREFETCHW m8 -- ditto, with some other hint */
9027 if (insn[0] == 0x0F && insn[1] == 0x0D
9028 && !epartIsReg(insn[2])
9029 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 1) {
9030 HChar* hintstr = "??";
9031
9032 modrm = getIByte(delta+2);
9033 vassert(!epartIsReg(modrm));
9034
9035 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9036 delta += 2+alen;
9037
9038 switch (gregOfRM(modrm)) {
9039 case 0: hintstr = ""; break;
9040 case 1: hintstr = "w"; break;
9041 default: vassert(0); /*NOTREACHED*/
9042 }
9043
9044 DIP("prefetch%s %s\n", hintstr, dis_buf);
9045 goto decode_success;
9046 }
9047
sewardj0bd7ce62004-12-05 02:47:40 +00009048 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9049 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
sewardj7b5b9982005-10-04 11:43:37 +00009050 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF6) {
sewardj0bd7ce62004-12-05 02:47:40 +00009051 do_MMX_preamble();
9052 delta = dis_MMXop_regmem_to_reg (
9053 sorb, delta+2, insn[1], "psadbw", False );
9054 goto decode_success;
9055 }
9056
9057 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9058 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
sewardjb9fa69b2004-12-09 23:25:14 +00009059 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
sewardj0bd7ce62004-12-05 02:47:40 +00009060 Int order;
sewardjb9fa69b2004-12-09 23:25:14 +00009061 IRTemp sV, dV, s3, s2, s1, s0;
9062 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9063 sV = newTemp(Ity_I64);
9064 dV = newTemp(Ity_I64);
sewardj0bd7ce62004-12-05 02:47:40 +00009065 do_MMX_preamble();
9066 modrm = insn[2];
9067 if (epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00009068 assign( sV, getMMXReg(eregOfRM(modrm)) );
sewardj0bd7ce62004-12-05 02:47:40 +00009069 order = (Int)insn[3];
9070 delta += 2+2;
9071 DIP("pshufw $%d,%s,%s\n", order,
9072 nameMMXReg(eregOfRM(modrm)),
9073 nameMMXReg(gregOfRM(modrm)));
9074 } else {
9075 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardjb9fa69b2004-12-09 23:25:14 +00009076 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
sewardj0bd7ce62004-12-05 02:47:40 +00009077 order = (Int)insn[2+alen];
9078 delta += 3+alen;
9079 DIP("pshufw $%d,%s,%s\n", order,
9080 dis_buf,
9081 nameMMXReg(gregOfRM(modrm)));
9082 }
sewardjb9fa69b2004-12-09 23:25:14 +00009083 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
sewardj0bd7ce62004-12-05 02:47:40 +00009084
sewardjb9fa69b2004-12-09 23:25:14 +00009085# define SEL(n) \
9086 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9087 assign(dV,
9088 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9089 SEL((order>>2)&3), SEL((order>>0)&3) )
sewardj0bd7ce62004-12-05 02:47:40 +00009090 );
sewardjb9fa69b2004-12-09 23:25:14 +00009091 putMMXReg(gregOfRM(modrm), mkexpr(dV));
sewardj0bd7ce62004-12-05 02:47:40 +00009092# undef SEL
sewardj0bd7ce62004-12-05 02:47:40 +00009093 goto decode_success;
9094 }
9095
9096 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
9097 if (insn[0] == 0x0F && insn[1] == 0x53) {
9098 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00009099 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9100 "rcpps", Iop_Recip32Fx4 );
sewardj0bd7ce62004-12-05 02:47:40 +00009101 goto decode_success;
9102 }
9103
9104 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
9105 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
9106 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00009107 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9108 "rcpss", Iop_Recip32F0x4 );
sewardj0bd7ce62004-12-05 02:47:40 +00009109 goto decode_success;
9110 }
sewardjb5452082004-12-04 20:33:02 +00009111
sewardjc1e7dfc2004-12-05 19:29:45 +00009112 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
9113 if (insn[0] == 0x0F && insn[1] == 0x52) {
9114 vassert(sz == 4);
9115 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9116 "rsqrtps", Iop_RSqrt32Fx4 );
9117 goto decode_success;
9118 }
9119
9120 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
9121 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
9122 vassert(sz == 4);
9123 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9124 "rsqrtss", Iop_RSqrt32F0x4 );
9125 goto decode_success;
9126 }
9127
9128 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
9129 if (insn[0] == 0x0F && insn[1] == 0xAE
sewardjc2feffc2004-12-08 12:31:22 +00009130 && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009131 vassert(sz == 4);
9132 delta += 3;
sewardj3e838932005-01-07 12:09:15 +00009133 /* Insert a memory fence. It's sometimes important that these
9134 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +00009135 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjc1e7dfc2004-12-05 19:29:45 +00009136 DIP("sfence\n");
9137 goto decode_success;
9138 }
9139
9140 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
sewardj008754b2004-12-08 14:37:10 +00009141 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009142 Int select;
9143 IRTemp sV, dV;
9144 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9145 sV = newTemp(Ity_V128);
9146 dV = newTemp(Ity_V128);
9147 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00009148 modrm = insn[2];
9149 assign( dV, getXMMReg(gregOfRM(modrm)) );
9150
9151 if (epartIsReg(modrm)) {
9152 assign( sV, getXMMReg(eregOfRM(modrm)) );
9153 select = (Int)insn[3];
9154 delta += 2+2;
9155 DIP("shufps $%d,%s,%s\n", select,
9156 nameXMMReg(eregOfRM(modrm)),
9157 nameXMMReg(gregOfRM(modrm)));
9158 } else {
9159 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9160 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9161 select = (Int)insn[2+alen];
9162 delta += 3+alen;
9163 DIP("shufps $%d,%s,%s\n", select,
9164 dis_buf,
9165 nameXMMReg(gregOfRM(modrm)));
9166 }
9167
9168 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9169 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9170
9171# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
9172# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9173
9174 putXMMReg(
9175 gregOfRM(modrm),
9176 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
9177 SELD((select>>2)&3), SELD((select>>0)&3) )
9178 );
9179
9180# undef SELD
9181# undef SELS
9182
9183 goto decode_success;
9184 }
9185
9186 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00009187 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009188 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9189 "sqrtps", Iop_Sqrt32Fx4 );
9190 goto decode_success;
9191 }
9192
9193 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9194 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
9195 vassert(sz == 4);
9196 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9197 "sqrtss", Iop_Sqrt32F0x4 );
9198 goto decode_success;
9199 }
9200
sewardja0e83b02005-01-06 12:36:38 +00009201 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
sewardj7df596b2004-12-06 14:29:12 +00009202 if (insn[0] == 0x0F && insn[1] == 0xAE
9203 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
9204 modrm = getIByte(delta+2);
9205 vassert(sz == 4);
9206 vassert(!epartIsReg(modrm));
9207
9208 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9209 delta += 2+alen;
9210
9211 /* Fake up a native SSE mxcsr word. The only thing it depends
9212 on is SSEROUND[1:0], so call a clean helper to cook it up.
9213 */
9214 /* UInt x86h_create_mxcsr ( UInt sseround ) */
sewardj33dd31b2005-01-08 18:17:32 +00009215 DIP("stmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00009216 storeLE( mkexpr(addr),
9217 mkIRExprCCall(
9218 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00009219 "x86g_create_mxcsr", &x86g_create_mxcsr,
sewardja0e83b02005-01-06 12:36:38 +00009220 mkIRExprVec_1( get_sse_roundingmode() )
sewardj7df596b2004-12-06 14:29:12 +00009221 )
9222 );
9223 goto decode_success;
9224 }
9225
sewardjc1e7dfc2004-12-05 19:29:45 +00009226 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00009227 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009228 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
9229 goto decode_success;
9230 }
9231
sewardj008754b2004-12-08 14:37:10 +00009232 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
sewardjc1e7dfc2004-12-05 19:29:45 +00009233 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
9234 vassert(sz == 4);
9235 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
9236 goto decode_success;
9237 }
9238
9239 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9240 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9241 /* These just appear to be special cases of SHUFPS */
sewardj008754b2004-12-08 14:37:10 +00009242 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009243 IRTemp sV, dV;
9244 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardj2d49b432005-02-01 00:37:06 +00009245 Bool hi = toBool(insn[1] == 0x15);
sewardjc1e7dfc2004-12-05 19:29:45 +00009246 sV = newTemp(Ity_V128);
9247 dV = newTemp(Ity_V128);
9248 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00009249 modrm = insn[2];
9250 assign( dV, getXMMReg(gregOfRM(modrm)) );
9251
9252 if (epartIsReg(modrm)) {
9253 assign( sV, getXMMReg(eregOfRM(modrm)) );
9254 delta += 2+1;
9255 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9256 nameXMMReg(eregOfRM(modrm)),
9257 nameXMMReg(gregOfRM(modrm)));
9258 } else {
9259 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9260 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9261 delta += 2+alen;
9262 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9263 dis_buf,
9264 nameXMMReg(gregOfRM(modrm)));
9265 }
9266
9267 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9268 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9269
9270 if (hi) {
9271 putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
9272 } else {
9273 putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
9274 }
9275
9276 goto decode_success;
9277 }
9278
9279 /* 0F 57 = XORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00009280 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +00009281 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_XorV128 );
sewardjc1e7dfc2004-12-05 19:29:45 +00009282 goto decode_success;
9283 }
9284
sewardj636ad762004-12-07 11:16:04 +00009285 /* ---------------------------------------------------- */
9286 /* --- end of the SSE decoder. --- */
9287 /* ---------------------------------------------------- */
9288
9289 /* ---------------------------------------------------- */
9290 /* --- start of the SSE2 decoder. --- */
9291 /* ---------------------------------------------------- */
9292
sewardj9df271d2004-12-31 22:37:42 +00009293 /* Skip parts of the decoder which don't apply given the stated
9294 guest subarchitecture. */
sewardj5117ce12006-01-27 21:20:15 +00009295 if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
9296 goto after_sse_decoders; /* no SSE2 capabilities */
sewardj9df271d2004-12-31 22:37:42 +00009297
sewardj636ad762004-12-07 11:16:04 +00009298 insn = (UChar*)&guest_code[delta];
9299
9300 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9301 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
9302 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
9303 goto decode_success;
9304 }
9305
9306 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9307 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
9308 vassert(sz == 4);
9309 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
9310 goto decode_success;
9311 }
9312
9313 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9314 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00009315 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00009316 goto decode_success;
9317 }
9318
9319 /* 66 0F 54 = ANDPD -- G = G and E */
9320 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00009321 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00009322 goto decode_success;
9323 }
9324
sewardjfd226452004-12-07 19:02:18 +00009325 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9326 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
9327 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
9328 goto decode_success;
9329 }
9330
9331 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9332 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
9333 vassert(sz == 4);
9334 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
9335 goto decode_success;
9336 }
9337
9338 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
9339 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
9340 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9341 IRTemp argL = newTemp(Ity_F64);
9342 IRTemp argR = newTemp(Ity_F64);
9343 modrm = getIByte(delta+2);
9344 if (epartIsReg(modrm)) {
9345 assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
9346 delta += 2+1;
9347 DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9348 nameXMMReg(gregOfRM(modrm)) );
9349 } else {
9350 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9351 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9352 delta += 2+alen;
9353 DIP("[u]comisd %s,%s\n", dis_buf,
9354 nameXMMReg(gregOfRM(modrm)) );
9355 }
9356 assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
9357
9358 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
9359 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
9360 stmt( IRStmt_Put(
9361 OFFB_CC_DEP1,
9362 binop( Iop_And32,
9363 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
9364 mkU32(0x45)
9365 )));
sewardja3b7e3a2005-04-05 01:54:19 +00009366 /* Set NDEP even though it isn't used. This makes redundant-PUT
9367 elimination of previous stores to this field work better. */
9368 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjfd226452004-12-07 19:02:18 +00009369 goto decode_success;
9370 }
9371
9372 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9373 F64 in xmm(G) */
9374 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
9375 IRTemp arg64 = newTemp(Ity_I64);
9376 vassert(sz == 4);
9377
9378 modrm = getIByte(delta+3);
9379 if (epartIsReg(modrm)) {
9380 assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
9381 delta += 3+1;
9382 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9383 nameXMMReg(gregOfRM(modrm)));
9384 } else {
9385 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9386 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9387 delta += 3+alen;
9388 DIP("cvtdq2pd %s,%s\n", dis_buf,
9389 nameXMMReg(gregOfRM(modrm)) );
9390 }
9391
9392 putXMMRegLane64F(
9393 gregOfRM(modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +00009394 unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)))
sewardjfd226452004-12-07 19:02:18 +00009395 );
9396
9397 putXMMRegLane64F(
9398 gregOfRM(modrm), 1,
sewardj6c299f32009-12-31 18:00:12 +00009399 unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)))
sewardjfd226452004-12-07 19:02:18 +00009400 );
9401
9402 goto decode_success;
9403 }
9404
9405 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9406 xmm(G) */
9407 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
9408 IRTemp argV = newTemp(Ity_V128);
9409 IRTemp rmode = newTemp(Ity_I32);
9410
9411 modrm = getIByte(delta+2);
9412 if (epartIsReg(modrm)) {
9413 assign( argV, getXMMReg(eregOfRM(modrm)) );
9414 delta += 2+1;
9415 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9416 nameXMMReg(gregOfRM(modrm)));
9417 } else {
9418 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9419 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9420 delta += 2+alen;
9421 DIP("cvtdq2ps %s,%s\n", dis_buf,
9422 nameXMMReg(gregOfRM(modrm)) );
9423 }
9424
9425 assign( rmode, get_sse_roundingmode() );
9426 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9427
9428# define CVT(_t) binop( Iop_F64toF32, \
9429 mkexpr(rmode), \
sewardj6c299f32009-12-31 18:00:12 +00009430 unop(Iop_I32StoF64,mkexpr(_t)))
sewardjfd226452004-12-07 19:02:18 +00009431
9432 putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
9433 putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
9434 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9435 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9436
9437# undef CVT
9438
9439 goto decode_success;
9440 }
9441
9442 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9443 lo half xmm(G), and zero upper half */
9444 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
9445 IRTemp argV = newTemp(Ity_V128);
9446 IRTemp rmode = newTemp(Ity_I32);
9447 vassert(sz == 4);
9448
9449 modrm = getIByte(delta+3);
9450 if (epartIsReg(modrm)) {
9451 assign( argV, getXMMReg(eregOfRM(modrm)) );
9452 delta += 3+1;
9453 DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9454 nameXMMReg(gregOfRM(modrm)));
9455 } else {
9456 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9457 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9458 delta += 3+alen;
9459 DIP("cvtpd2dq %s,%s\n", dis_buf,
9460 nameXMMReg(gregOfRM(modrm)) );
9461 }
9462
9463 assign( rmode, get_sse_roundingmode() );
9464 t0 = newTemp(Ity_F64);
9465 t1 = newTemp(Ity_F64);
9466 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009467 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009468 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009469 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009470
sewardj6c299f32009-12-31 18:00:12 +00009471# define CVT(_t) binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +00009472 mkexpr(rmode), \
9473 mkexpr(_t) )
9474
9475 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9476 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9477 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9478 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9479
9480# undef CVT
9481
9482 goto decode_success;
9483 }
9484
9485 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9486 I32 in mmx, according to prevailing SSE rounding mode */
9487 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9488 I32 in mmx, rounding towards zero */
9489 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9490 IRTemp dst64 = newTemp(Ity_I64);
9491 IRTemp rmode = newTemp(Ity_I32);
9492 IRTemp f64lo = newTemp(Ity_F64);
9493 IRTemp f64hi = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00009494 Bool r2zero = toBool(insn[1] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00009495
9496 do_MMX_preamble();
9497 modrm = getIByte(delta+2);
9498
9499 if (epartIsReg(modrm)) {
9500 delta += 2+1;
9501 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9502 assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
9503 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9504 nameXMMReg(eregOfRM(modrm)),
9505 nameMMXReg(gregOfRM(modrm)));
9506 } else {
9507 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9508 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9509 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
9510 mkexpr(addr),
9511 mkU32(8) )));
9512 delta += 2+alen;
9513 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9514 dis_buf,
9515 nameMMXReg(gregOfRM(modrm)));
9516 }
9517
9518 if (r2zero) {
9519 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9520 } else {
9521 assign( rmode, get_sse_roundingmode() );
9522 }
9523
9524 assign(
9525 dst64,
9526 binop( Iop_32HLto64,
sewardj6c299f32009-12-31 18:00:12 +00009527 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64hi) ),
9528 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo) )
sewardjfd226452004-12-07 19:02:18 +00009529 )
9530 );
9531
9532 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
9533 goto decode_success;
9534 }
9535
9536 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9537 lo half xmm(G), and zero upper half */
9538 /* Note, this is practically identical to CVTPD2DQ. It would have
9539 been nicer to merge them together, but the insn[] offsets differ
9540 by one. */
9541 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
9542 IRTemp argV = newTemp(Ity_V128);
9543 IRTemp rmode = newTemp(Ity_I32);
9544
9545 modrm = getIByte(delta+2);
9546 if (epartIsReg(modrm)) {
9547 assign( argV, getXMMReg(eregOfRM(modrm)) );
9548 delta += 2+1;
9549 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9550 nameXMMReg(gregOfRM(modrm)));
9551 } else {
9552 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9553 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9554 delta += 2+alen;
9555 DIP("cvtpd2ps %s,%s\n", dis_buf,
9556 nameXMMReg(gregOfRM(modrm)) );
9557 }
9558
9559 assign( rmode, get_sse_roundingmode() );
9560 t0 = newTemp(Ity_F64);
9561 t1 = newTemp(Ity_F64);
9562 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009563 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009564 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009565 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009566
9567# define CVT(_t) binop( Iop_F64toF32, \
9568 mkexpr(rmode), \
9569 mkexpr(_t) )
9570
9571 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9572 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9573 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9574 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9575
9576# undef CVT
9577
9578 goto decode_success;
9579 }
9580
9581 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9582 xmm(G) */
9583 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
9584 IRTemp arg64 = newTemp(Ity_I64);
9585
9586 modrm = getIByte(delta+2);
sewardjfd226452004-12-07 19:02:18 +00009587 if (epartIsReg(modrm)) {
sewardj30a20e92010-02-21 20:40:53 +00009588 /* Only switch to MMX mode if the source is a MMX register.
9589 This is inconsistent with all other instructions which
9590 convert between XMM and (M64 or MMX), which always switch
9591 to MMX mode even if 64-bit operand is M64 and not MMX. At
9592 least, that's what the Intel docs seem to me to say.
9593 Fixes #210264. */
9594 do_MMX_preamble();
sewardjfd226452004-12-07 19:02:18 +00009595 assign( arg64, getMMXReg(eregOfRM(modrm)) );
9596 delta += 2+1;
9597 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9598 nameXMMReg(gregOfRM(modrm)));
9599 } else {
9600 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9601 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9602 delta += 2+alen;
9603 DIP("cvtpi2pd %s,%s\n", dis_buf,
9604 nameXMMReg(gregOfRM(modrm)) );
9605 }
9606
9607 putXMMRegLane64F(
9608 gregOfRM(modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +00009609 unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)) )
sewardjfd226452004-12-07 19:02:18 +00009610 );
9611
9612 putXMMRegLane64F(
9613 gregOfRM(modrm), 1,
sewardj6c299f32009-12-31 18:00:12 +00009614 unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)) )
sewardjfd226452004-12-07 19:02:18 +00009615 );
9616
9617 goto decode_success;
9618 }
9619
9620 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9621 xmm(G) */
9622 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
9623 IRTemp argV = newTemp(Ity_V128);
9624 IRTemp rmode = newTemp(Ity_I32);
9625
9626 modrm = getIByte(delta+2);
9627 if (epartIsReg(modrm)) {
9628 assign( argV, getXMMReg(eregOfRM(modrm)) );
9629 delta += 2+1;
9630 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9631 nameXMMReg(gregOfRM(modrm)));
9632 } else {
9633 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9634 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9635 delta += 2+alen;
9636 DIP("cvtps2dq %s,%s\n", dis_buf,
9637 nameXMMReg(gregOfRM(modrm)) );
9638 }
9639
9640 assign( rmode, get_sse_roundingmode() );
9641 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9642
9643 /* This is less than ideal. If it turns out to be a performance
9644 bottleneck it can be improved. */
9645# define CVT(_t) \
sewardj6c299f32009-12-31 18:00:12 +00009646 binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +00009647 mkexpr(rmode), \
9648 unop( Iop_F32toF64, \
9649 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9650
9651 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9652 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9653 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9654 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9655
9656# undef CVT
9657
9658 goto decode_success;
9659 }
9660
9661 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9662 F64 in xmm(G). */
9663 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
9664 IRTemp f32lo = newTemp(Ity_F32);
9665 IRTemp f32hi = newTemp(Ity_F32);
9666
9667 modrm = getIByte(delta+2);
9668 if (epartIsReg(modrm)) {
9669 assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
9670 assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
9671 delta += 2+1;
9672 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9673 nameXMMReg(gregOfRM(modrm)));
9674 } else {
9675 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9676 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9677 assign( f32hi, loadLE(Ity_F32,
9678 binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
9679 delta += 2+alen;
9680 DIP("cvtps2pd %s,%s\n", dis_buf,
9681 nameXMMReg(gregOfRM(modrm)) );
9682 }
9683
9684 putXMMRegLane64F( gregOfRM(modrm), 1,
9685 unop(Iop_F32toF64, mkexpr(f32hi)) );
9686 putXMMRegLane64F( gregOfRM(modrm), 0,
9687 unop(Iop_F32toF64, mkexpr(f32lo)) );
9688
9689 goto decode_success;
9690 }
9691
9692 /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
9693 I32 in ireg, according to prevailing SSE rounding mode */
9694 /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
sewardj0b210442005-02-23 13:28:27 +00009695 I32 in ireg, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00009696 if (insn[0] == 0xF2 && insn[1] == 0x0F
9697 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
9698 IRTemp rmode = newTemp(Ity_I32);
9699 IRTemp f64lo = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00009700 Bool r2zero = toBool(insn[2] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00009701 vassert(sz == 4);
9702
9703 modrm = getIByte(delta+3);
9704 if (epartIsReg(modrm)) {
9705 delta += 3+1;
9706 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9707 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9708 nameXMMReg(eregOfRM(modrm)),
9709 nameIReg(4, gregOfRM(modrm)));
9710 } else {
9711 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9712 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9713 delta += 3+alen;
9714 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9715 dis_buf,
9716 nameIReg(4, gregOfRM(modrm)));
9717 }
9718
9719 if (r2zero) {
9720 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9721 } else {
9722 assign( rmode, get_sse_roundingmode() );
9723 }
9724
9725 putIReg(4, gregOfRM(modrm),
sewardj6c299f32009-12-31 18:00:12 +00009726 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo)) );
sewardjfd226452004-12-07 19:02:18 +00009727
9728 goto decode_success;
9729 }
9730
9731 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
9732 low 1/4 xmm(G), according to prevailing SSE rounding mode */
9733 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
9734 IRTemp rmode = newTemp(Ity_I32);
9735 IRTemp f64lo = newTemp(Ity_F64);
9736 vassert(sz == 4);
9737
9738 modrm = getIByte(delta+3);
9739 if (epartIsReg(modrm)) {
9740 delta += 3+1;
9741 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9742 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9743 nameXMMReg(gregOfRM(modrm)));
9744 } else {
9745 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9746 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9747 delta += 3+alen;
9748 DIP("cvtsd2ss %s,%s\n", dis_buf,
9749 nameXMMReg(gregOfRM(modrm)));
9750 }
9751
9752 assign( rmode, get_sse_roundingmode() );
9753 putXMMRegLane32F(
9754 gregOfRM(modrm), 0,
9755 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
9756 );
9757
9758 goto decode_success;
9759 }
9760
9761 /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
9762 half xmm */
9763 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
9764 IRTemp arg32 = newTemp(Ity_I32);
9765 vassert(sz == 4);
9766
9767 modrm = getIByte(delta+3);
sewardjfd226452004-12-07 19:02:18 +00009768 if (epartIsReg(modrm)) {
9769 assign( arg32, getIReg(4, eregOfRM(modrm)) );
9770 delta += 3+1;
9771 DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
9772 nameXMMReg(gregOfRM(modrm)));
9773 } else {
9774 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9775 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
9776 delta += 3+alen;
9777 DIP("cvtsi2sd %s,%s\n", dis_buf,
9778 nameXMMReg(gregOfRM(modrm)) );
9779 }
9780
9781 putXMMRegLane64F(
9782 gregOfRM(modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +00009783 unop(Iop_I32StoF64, mkexpr(arg32)) );
sewardjfd226452004-12-07 19:02:18 +00009784
9785 goto decode_success;
9786 }
9787
9788 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
9789 low half xmm(G) */
9790 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
9791 IRTemp f32lo = newTemp(Ity_F32);
9792 vassert(sz == 4);
9793
9794 modrm = getIByte(delta+3);
9795 if (epartIsReg(modrm)) {
9796 delta += 3+1;
9797 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
9798 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9799 nameXMMReg(gregOfRM(modrm)));
9800 } else {
9801 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9802 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
9803 delta += 3+alen;
9804 DIP("cvtss2sd %s,%s\n", dis_buf,
9805 nameXMMReg(gregOfRM(modrm)));
9806 }
9807
9808 putXMMRegLane64F( gregOfRM(modrm), 0,
9809 unop( Iop_F32toF64, mkexpr(f32lo) ) );
9810
9811 goto decode_success;
9812 }
9813
9814 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9815 lo half xmm(G), and zero upper half, rounding towards zero */
9816 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
9817 IRTemp argV = newTemp(Ity_V128);
9818 IRTemp rmode = newTemp(Ity_I32);
9819
9820 modrm = getIByte(delta+2);
9821 if (epartIsReg(modrm)) {
9822 assign( argV, getXMMReg(eregOfRM(modrm)) );
9823 delta += 2+1;
9824 DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9825 nameXMMReg(gregOfRM(modrm)));
9826 } else {
9827 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9828 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9829 delta += 2+alen;
9830 DIP("cvttpd2dq %s,%s\n", dis_buf,
9831 nameXMMReg(gregOfRM(modrm)) );
9832 }
9833
9834 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9835
9836 t0 = newTemp(Ity_F64);
9837 t1 = newTemp(Ity_F64);
9838 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009839 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009840 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009841 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009842
sewardj6c299f32009-12-31 18:00:12 +00009843# define CVT(_t) binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +00009844 mkexpr(rmode), \
9845 mkexpr(_t) )
9846
9847 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9848 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9849 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9850 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9851
9852# undef CVT
9853
9854 goto decode_success;
9855 }
9856
9857 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9858 xmm(G), rounding towards zero */
9859 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
9860 IRTemp argV = newTemp(Ity_V128);
9861 IRTemp rmode = newTemp(Ity_I32);
9862 vassert(sz == 4);
9863
9864 modrm = getIByte(delta+3);
9865 if (epartIsReg(modrm)) {
9866 assign( argV, getXMMReg(eregOfRM(modrm)) );
9867 delta += 3+1;
9868 DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9869 nameXMMReg(gregOfRM(modrm)));
9870 } else {
9871 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9872 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9873 delta += 3+alen;
9874 DIP("cvttps2dq %s,%s\n", dis_buf,
9875 nameXMMReg(gregOfRM(modrm)) );
9876 }
9877
9878 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9879 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9880
9881 /* This is less than ideal. If it turns out to be a performance
9882 bottleneck it can be improved. */
9883# define CVT(_t) \
sewardj6c299f32009-12-31 18:00:12 +00009884 binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +00009885 mkexpr(rmode), \
9886 unop( Iop_F32toF64, \
9887 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9888
9889 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9890 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9891 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9892 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9893
9894# undef CVT
9895
9896 goto decode_success;
9897 }
9898
9899 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
9900 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
9901 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
9902 goto decode_success;
9903 }
9904
sewardjc2feffc2004-12-08 12:31:22 +00009905 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
9906 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5E) {
9907 vassert(sz == 4);
9908 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "divsd", Iop_Div64F0x2 );
9909 goto decode_success;
9910 }
9911
9912 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
9913 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
9914 if (insn[0] == 0x0F && insn[1] == 0xAE
9915 && epartIsReg(insn[2])
9916 && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
9917 vassert(sz == 4);
9918 delta += 3;
sewardj3e838932005-01-07 12:09:15 +00009919 /* Insert a memory fence. It's sometimes important that these
9920 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +00009921 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjc2feffc2004-12-08 12:31:22 +00009922 DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
9923 goto decode_success;
9924 }
9925
9926 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
9927 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
9928 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
9929 goto decode_success;
9930 }
9931
9932 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
9933 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5F) {
9934 vassert(sz == 4);
9935 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "maxsd", Iop_Max64F0x2 );
9936 goto decode_success;
9937 }
9938
9939 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
9940 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
9941 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
9942 goto decode_success;
9943 }
9944
9945 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
9946 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) {
9947 vassert(sz == 4);
9948 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 );
9949 goto decode_success;
9950 }
9951
9952 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
9953 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
9954 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
9955 if (sz == 2 && insn[0] == 0x0F
9956 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
9957 HChar* wot = insn[1]==0x28 ? "apd" :
9958 insn[1]==0x10 ? "upd" : "dqa";
9959 modrm = getIByte(delta+2);
9960 if (epartIsReg(modrm)) {
9961 putXMMReg( gregOfRM(modrm),
9962 getXMMReg( eregOfRM(modrm) ));
9963 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)),
9964 nameXMMReg(gregOfRM(modrm)));
9965 delta += 2+1;
9966 } else {
9967 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +00009968 if (insn[1] == 0x28/*movapd*/ || insn[1] == 0x6F/*movdqa*/)
9969 gen_SEGV_if_not_16_aligned( addr );
sewardjc2feffc2004-12-08 12:31:22 +00009970 putXMMReg( gregOfRM(modrm),
9971 loadLE(Ity_V128, mkexpr(addr)) );
9972 DIP("mov%s %s,%s\n", wot, dis_buf,
9973 nameXMMReg(gregOfRM(modrm)));
9974 delta += 2+alen;
9975 }
9976 goto decode_success;
9977 }
9978
sewardj95535fe2004-12-15 17:42:58 +00009979 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj1c318772005-03-19 14:27:04 +00009980 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
9981 if (sz == 2 && insn[0] == 0x0F
9982 && (insn[1] == 0x29 || insn[1] == 0x11)) {
9983 HChar* wot = insn[1]==0x29 ? "apd" : "upd";
sewardj95535fe2004-12-15 17:42:58 +00009984 modrm = getIByte(delta+2);
9985 if (epartIsReg(modrm)) {
9986 /* fall through; awaiting test case */
9987 } else {
9988 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +00009989 if (insn[1] == 0x29/*movapd*/)
9990 gen_SEGV_if_not_16_aligned( addr );
sewardj95535fe2004-12-15 17:42:58 +00009991 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj1c318772005-03-19 14:27:04 +00009992 DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRM(modrm)),
9993 dis_buf );
sewardj95535fe2004-12-15 17:42:58 +00009994 delta += 2+alen;
9995 goto decode_success;
9996 }
9997 }
9998
sewardjc2feffc2004-12-08 12:31:22 +00009999 /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
10000 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
10001 modrm = getIByte(delta+2);
10002 if (epartIsReg(modrm)) {
10003 delta += 2+1;
10004 putXMMReg(
10005 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010006 unop( Iop_32UtoV128, getIReg(4, eregOfRM(modrm)) )
sewardjc2feffc2004-12-08 12:31:22 +000010007 );
10008 DIP("movd %s, %s\n",
10009 nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
10010 } else {
10011 addr = disAMode( &alen, sorb, delta+2, dis_buf );
10012 delta += 2+alen;
10013 putXMMReg(
10014 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010015 unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
sewardjc2feffc2004-12-08 12:31:22 +000010016 );
10017 DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
10018 }
10019 goto decode_success;
10020 }
10021
10022 /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
10023 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
10024 modrm = getIByte(delta+2);
10025 if (epartIsReg(modrm)) {
10026 delta += 2+1;
10027 putIReg( 4, eregOfRM(modrm),
10028 getXMMRegLane32(gregOfRM(modrm), 0) );
10029 DIP("movd %s, %s\n",
10030 nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
10031 } else {
10032 addr = disAMode( &alen, sorb, delta+2, dis_buf );
10033 delta += 2+alen;
10034 storeLE( mkexpr(addr),
10035 getXMMRegLane32(gregOfRM(modrm), 0) );
10036 DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10037 }
10038 goto decode_success;
10039 }
10040
10041 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
10042 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
10043 modrm = getIByte(delta+2);
10044 if (epartIsReg(modrm)) {
10045 delta += 2+1;
10046 putXMMReg( eregOfRM(modrm),
10047 getXMMReg(gregOfRM(modrm)) );
10048 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10049 nameXMMReg(eregOfRM(modrm)));
10050 } else {
10051 addr = disAMode( &alen, sorb, delta+2, dis_buf );
10052 delta += 2+alen;
sewardj45ca0b92010-09-30 14:51:51 +000010053 gen_SEGV_if_not_16_aligned( addr );
sewardjc2feffc2004-12-08 12:31:22 +000010054 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10055 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10056 }
10057 goto decode_success;
10058 }
10059
10060 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
10061 /* Unfortunately can't simply use the MOVDQA case since the
10062 prefix lengths are different (66 vs F3) */
10063 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
10064 vassert(sz == 4);
10065 modrm = getIByte(delta+3);
10066 if (epartIsReg(modrm)) {
10067 putXMMReg( gregOfRM(modrm),
10068 getXMMReg( eregOfRM(modrm) ));
10069 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10070 nameXMMReg(gregOfRM(modrm)));
10071 delta += 3+1;
10072 } else {
10073 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10074 putXMMReg( gregOfRM(modrm),
10075 loadLE(Ity_V128, mkexpr(addr)) );
10076 DIP("movdqu %s,%s\n", dis_buf,
10077 nameXMMReg(gregOfRM(modrm)));
10078 delta += 3+alen;
10079 }
10080 goto decode_success;
10081 }
10082
10083 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
10084 /* Unfortunately can't simply use the MOVDQA case since the
10085 prefix lengths are different (66 vs F3) */
10086 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
10087 vassert(sz == 4);
10088 modrm = getIByte(delta+3);
10089 if (epartIsReg(modrm)) {
10090 delta += 3+1;
10091 putXMMReg( eregOfRM(modrm),
10092 getXMMReg(gregOfRM(modrm)) );
10093 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10094 nameXMMReg(eregOfRM(modrm)));
10095 } else {
10096 addr = disAMode( &alen, sorb, delta+3, dis_buf );
10097 delta += 3+alen;
10098 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10099 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10100 }
10101 goto decode_success;
10102 }
10103
10104 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
10105 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
10106 vassert(sz == 4);
10107 modrm = getIByte(delta+3);
10108 if (epartIsReg(modrm)) {
10109 do_MMX_preamble();
10110 putMMXReg( gregOfRM(modrm),
10111 getXMMRegLane64( eregOfRM(modrm), 0 ));
10112 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10113 nameMMXReg(gregOfRM(modrm)));
10114 delta += 3+1;
10115 goto decode_success;
10116 } else {
10117 /* fall through, apparently no mem case for this insn */
10118 }
10119 }
10120
10121 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
10122 /* These seems identical to MOVHPS. This instruction encoding is
10123 completely crazy. */
10124 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
10125 modrm = getIByte(delta+2);
10126 if (epartIsReg(modrm)) {
10127 /* fall through; apparently reg-reg is not possible */
10128 } else {
10129 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10130 delta += 2+alen;
10131 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
10132 loadLE(Ity_I64, mkexpr(addr)) );
10133 DIP("movhpd %s,%s\n", dis_buf,
10134 nameXMMReg( gregOfRM(modrm) ));
10135 goto decode_success;
10136 }
10137 }
10138
10139 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
10140 /* Again, this seems identical to MOVHPS. */
10141 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
10142 if (!epartIsReg(insn[2])) {
10143 delta += 2;
10144 addr = disAMode ( &alen, sorb, delta, dis_buf );
10145 delta += alen;
10146 storeLE( mkexpr(addr),
10147 getXMMRegLane64( gregOfRM(insn[2]),
10148 1/*upper lane*/ ) );
10149 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
10150 dis_buf);
10151 goto decode_success;
10152 }
10153 /* else fall through */
10154 }
10155
10156 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
10157 /* Identical to MOVLPS ? */
10158 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x12) {
10159 modrm = getIByte(delta+2);
10160 if (epartIsReg(modrm)) {
10161 /* fall through; apparently reg-reg is not possible */
10162 } else {
10163 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10164 delta += 2+alen;
10165 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
10166 loadLE(Ity_I64, mkexpr(addr)) );
10167 DIP("movlpd %s, %s\n",
10168 dis_buf, nameXMMReg( gregOfRM(modrm) ));
10169 goto decode_success;
10170 }
10171 }
10172
10173 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
10174 /* Identical to MOVLPS ? */
10175 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
10176 if (!epartIsReg(insn[2])) {
10177 delta += 2;
10178 addr = disAMode ( &alen, sorb, delta, dis_buf );
10179 delta += alen;
10180 storeLE( mkexpr(addr),
10181 getXMMRegLane64( gregOfRM(insn[2]),
10182 0/*lower lane*/ ) );
10183 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
10184 dis_buf);
10185 goto decode_success;
10186 }
10187 /* else fall through */
10188 }
10189
10190 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10191 2 lowest bits of ireg(G) */
10192 if (insn[0] == 0x0F && insn[1] == 0x50) {
10193 modrm = getIByte(delta+2);
10194 if (sz == 2 && epartIsReg(modrm)) {
10195 Int src;
10196 t0 = newTemp(Ity_I32);
10197 t1 = newTemp(Ity_I32);
10198 delta += 2+1;
10199 src = eregOfRM(modrm);
10200 assign( t0, binop( Iop_And32,
10201 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10202 mkU32(1) ));
10203 assign( t1, binop( Iop_And32,
10204 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10205 mkU32(2) ));
10206 putIReg(4, gregOfRM(modrm),
10207 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10208 );
10209 DIP("movmskpd %s,%s\n", nameXMMReg(src),
10210 nameIReg(4, gregOfRM(modrm)));
10211 goto decode_success;
10212 }
10213 /* else fall through */
10214 }
10215
sewardjd71ba832006-12-27 01:15:29 +000010216 /* 66 0F F7 = MASKMOVDQU -- store selected bytes of double quadword */
10217 if (insn[0] == 0x0F && insn[1] == 0xF7) {
10218 modrm = getIByte(delta+2);
10219 if (sz == 2 && epartIsReg(modrm)) {
10220 IRTemp regD = newTemp(Ity_V128);
10221 IRTemp mask = newTemp(Ity_V128);
10222 IRTemp olddata = newTemp(Ity_V128);
10223 IRTemp newdata = newTemp(Ity_V128);
10224 addr = newTemp(Ity_I32);
10225
10226 assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
10227 assign( regD, getXMMReg( gregOfRM(modrm) ));
10228
10229 /* Unfortunately can't do the obvious thing with SarN8x16
10230 here since that can't be re-emitted as SSE2 code - no such
10231 insn. */
10232 assign(
10233 mask,
10234 binop(Iop_64HLtoV128,
10235 binop(Iop_SarN8x8,
10236 getXMMRegLane64( eregOfRM(modrm), 1 ),
10237 mkU8(7) ),
10238 binop(Iop_SarN8x8,
10239 getXMMRegLane64( eregOfRM(modrm), 0 ),
10240 mkU8(7) ) ));
10241 assign( olddata, loadLE( Ity_V128, mkexpr(addr) ));
10242 assign( newdata,
10243 binop(Iop_OrV128,
10244 binop(Iop_AndV128,
10245 mkexpr(regD),
10246 mkexpr(mask) ),
10247 binop(Iop_AndV128,
10248 mkexpr(olddata),
10249 unop(Iop_NotV128, mkexpr(mask)))) );
10250 storeLE( mkexpr(addr), mkexpr(newdata) );
10251
10252 delta += 2+1;
10253 DIP("maskmovdqu %s,%s\n", nameXMMReg( eregOfRM(modrm) ),
10254 nameXMMReg( gregOfRM(modrm) ) );
10255 goto decode_success;
10256 }
10257 /* else fall through */
10258 }
10259
sewardjc2feffc2004-12-08 12:31:22 +000010260 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10261 if (insn[0] == 0x0F && insn[1] == 0xE7) {
10262 modrm = getIByte(delta+2);
10263 if (sz == 2 && !epartIsReg(modrm)) {
10264 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +000010265 gen_SEGV_if_not_16_aligned( addr );
sewardjc2feffc2004-12-08 12:31:22 +000010266 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10267 DIP("movntdq %s,%s\n", dis_buf,
10268 nameXMMReg(gregOfRM(modrm)));
10269 delta += 2+alen;
10270 goto decode_success;
10271 }
10272 /* else fall through */
10273 }
10274
10275 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10276 if (insn[0] == 0x0F && insn[1] == 0xC3) {
10277 vassert(sz == 4);
10278 modrm = getIByte(delta+2);
10279 if (!epartIsReg(modrm)) {
10280 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10281 storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
10282 DIP("movnti %s,%s\n", dis_buf,
10283 nameIReg(4, gregOfRM(modrm)));
10284 delta += 2+alen;
10285 goto decode_success;
10286 }
10287 /* else fall through */
10288 }
10289
sewardj95535fe2004-12-15 17:42:58 +000010290 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
10291 or lo half xmm). */
sewardj9ee82862004-12-14 01:16:59 +000010292 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
10293 modrm = getIByte(delta+2);
10294 if (epartIsReg(modrm)) {
10295 /* fall through, awaiting test case */
sewardj6d7ccd52005-05-14 02:04:12 +000010296 /* dst: lo half copied, hi half zeroed */
sewardj9ee82862004-12-14 01:16:59 +000010297 } else {
10298 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10299 storeLE( mkexpr(addr),
10300 getXMMRegLane64( gregOfRM(modrm), 0 ));
10301 DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
10302 delta += 2+alen;
10303 goto decode_success;
10304 }
10305 }
10306
sewardjc2feffc2004-12-08 12:31:22 +000010307 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10308 hi half). */
10309 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
10310 vassert(sz == 4);
10311 modrm = getIByte(delta+3);
10312 if (epartIsReg(modrm)) {
10313 do_MMX_preamble();
10314 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010315 unop(Iop_64UtoV128, getMMXReg( eregOfRM(modrm) )) );
sewardjc2feffc2004-12-08 12:31:22 +000010316 DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10317 nameXMMReg(gregOfRM(modrm)));
10318 delta += 3+1;
10319 goto decode_success;
10320 } else {
10321 /* fall through, apparently no mem case for this insn */
10322 }
10323 }
10324
sewardj95535fe2004-12-15 17:42:58 +000010325 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj6d7ccd52005-05-14 02:04:12 +000010326 G (lo half xmm). Upper half of G is zeroed out. */
sewardj95535fe2004-12-15 17:42:58 +000010327 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
10328 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj6d7ccd52005-05-14 02:04:12 +000010329 If E is reg, upper half of G is unchanged. */
sewardj95535fe2004-12-15 17:42:58 +000010330 if ((insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x10)
10331 || (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7E)) {
sewardjc2feffc2004-12-08 12:31:22 +000010332 vassert(sz == 4);
10333 modrm = getIByte(delta+3);
10334 if (epartIsReg(modrm)) {
10335 putXMMRegLane64( gregOfRM(modrm), 0,
10336 getXMMRegLane64( eregOfRM(modrm), 0 ));
sewardj6d7ccd52005-05-14 02:04:12 +000010337 if (insn[0] == 0xF3/*MOVQ*/) {
10338 /* zero bits 127:64 */
10339 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
10340 }
sewardjc2feffc2004-12-08 12:31:22 +000010341 DIP("movsd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10342 nameXMMReg(gregOfRM(modrm)));
10343 delta += 3+1;
10344 } else {
10345 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +000010346 /* zero bits 127:64 */
sewardj5bf1fd42005-04-06 01:11:08 +000010347 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
sewardjad50db02005-04-06 01:45:44 +000010348 /* write bits 63:0 */
sewardjc2feffc2004-12-08 12:31:22 +000010349 putXMMRegLane64( gregOfRM(modrm), 0,
10350 loadLE(Ity_I64, mkexpr(addr)) );
10351 DIP("movsd %s,%s\n", dis_buf,
10352 nameXMMReg(gregOfRM(modrm)));
10353 delta += 3+alen;
10354 }
10355 goto decode_success;
10356 }
10357
10358 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10359 or lo half xmm). */
10360 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x11) {
10361 vassert(sz == 4);
10362 modrm = getIByte(delta+3);
10363 if (epartIsReg(modrm)) {
sewardjb7ba04f2008-11-17 20:25:37 +000010364 putXMMRegLane64( eregOfRM(modrm), 0,
10365 getXMMRegLane64( gregOfRM(modrm), 0 ));
10366 DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
10367 nameXMMReg(eregOfRM(modrm)));
10368 delta += 3+1;
sewardjc2feffc2004-12-08 12:31:22 +000010369 } else {
10370 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10371 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +000010372 getXMMRegLane64(gregOfRM(modrm), 0) );
10373 DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardjc2feffc2004-12-08 12:31:22 +000010374 dis_buf);
10375 delta += 3+alen;
sewardjc2feffc2004-12-08 12:31:22 +000010376 }
sewardjb7ba04f2008-11-17 20:25:37 +000010377 goto decode_success;
sewardjc2feffc2004-12-08 12:31:22 +000010378 }
sewardjfd226452004-12-07 19:02:18 +000010379
sewardj008754b2004-12-08 14:37:10 +000010380 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10381 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
10382 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
10383 goto decode_success;
10384 }
10385
10386 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
10387 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
10388 vassert(sz == 4);
10389 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
10390 goto decode_success;
10391 }
10392
10393 /* 66 0F 56 = ORPD -- G = G and E */
10394 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +000010395 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_OrV128 );
sewardj008754b2004-12-08 14:37:10 +000010396 goto decode_success;
10397 }
10398
10399 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10400 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
10401 Int select;
10402 IRTemp sV = newTemp(Ity_V128);
10403 IRTemp dV = newTemp(Ity_V128);
10404 IRTemp s1 = newTemp(Ity_I64);
10405 IRTemp s0 = newTemp(Ity_I64);
10406 IRTemp d1 = newTemp(Ity_I64);
10407 IRTemp d0 = newTemp(Ity_I64);
10408
10409 modrm = insn[2];
10410 assign( dV, getXMMReg(gregOfRM(modrm)) );
10411
10412 if (epartIsReg(modrm)) {
10413 assign( sV, getXMMReg(eregOfRM(modrm)) );
10414 select = (Int)insn[3];
10415 delta += 2+2;
10416 DIP("shufpd $%d,%s,%s\n", select,
10417 nameXMMReg(eregOfRM(modrm)),
10418 nameXMMReg(gregOfRM(modrm)));
10419 } else {
10420 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10421 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10422 select = (Int)insn[2+alen];
10423 delta += 3+alen;
10424 DIP("shufpd $%d,%s,%s\n", select,
10425 dis_buf,
10426 nameXMMReg(gregOfRM(modrm)));
10427 }
10428
sewardjf0c1c582005-02-07 23:47:38 +000010429 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10430 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10431 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10432 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +000010433
10434# define SELD(n) mkexpr((n)==0 ? d0 : d1)
10435# define SELS(n) mkexpr((n)==0 ? s0 : s1)
10436
10437 putXMMReg(
10438 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010439 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
sewardj008754b2004-12-08 14:37:10 +000010440 );
10441
10442# undef SELD
10443# undef SELS
10444
10445 goto decode_success;
10446 }
10447
10448 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10449 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
10450 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
10451 "sqrtpd", Iop_Sqrt64Fx2 );
10452 goto decode_success;
10453 }
10454
10455 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10456 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
10457 vassert(sz == 4);
10458 delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3,
10459 "sqrtsd", Iop_Sqrt64F0x2 );
10460 goto decode_success;
10461 }
10462
10463 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10464 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
10465 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
10466 goto decode_success;
10467 }
10468
10469 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10470 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
10471 vassert(sz == 4);
10472 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
10473 goto decode_success;
10474 }
10475
10476 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10477 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10478 /* These just appear to be special cases of SHUFPS */
10479 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10480 IRTemp s1 = newTemp(Ity_I64);
10481 IRTemp s0 = newTemp(Ity_I64);
10482 IRTemp d1 = newTemp(Ity_I64);
10483 IRTemp d0 = newTemp(Ity_I64);
10484 IRTemp sV = newTemp(Ity_V128);
10485 IRTemp dV = newTemp(Ity_V128);
sewardj2d49b432005-02-01 00:37:06 +000010486 Bool hi = toBool(insn[1] == 0x15);
sewardj008754b2004-12-08 14:37:10 +000010487
10488 modrm = insn[2];
10489 assign( dV, getXMMReg(gregOfRM(modrm)) );
10490
10491 if (epartIsReg(modrm)) {
10492 assign( sV, getXMMReg(eregOfRM(modrm)) );
10493 delta += 2+1;
10494 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10495 nameXMMReg(eregOfRM(modrm)),
10496 nameXMMReg(gregOfRM(modrm)));
10497 } else {
10498 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10499 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10500 delta += 2+alen;
10501 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10502 dis_buf,
10503 nameXMMReg(gregOfRM(modrm)));
10504 }
10505
sewardjf0c1c582005-02-07 23:47:38 +000010506 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10507 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10508 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10509 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +000010510
10511 if (hi) {
10512 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010513 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
sewardj008754b2004-12-08 14:37:10 +000010514 } else {
10515 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010516 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
sewardj008754b2004-12-08 14:37:10 +000010517 }
10518
10519 goto decode_success;
10520 }
10521
10522 /* 66 0F 57 = XORPD -- G = G and E */
10523 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +000010524 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_XorV128 );
sewardj008754b2004-12-08 14:37:10 +000010525 goto decode_success;
10526 }
sewardj636ad762004-12-07 11:16:04 +000010527
sewardj164f9272004-12-09 00:39:32 +000010528 /* 66 0F 6B = PACKSSDW */
10529 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
10530 delta = dis_SSEint_E_to_G( sorb, delta+2,
sewardjc9bff7d2011-06-15 15:09:37 +000010531 "packssdw",
sewardj5f438dd2011-06-16 11:36:23 +000010532 Iop_QNarrowBin32Sto16Sx8, True );
sewardj164f9272004-12-09 00:39:32 +000010533 goto decode_success;
10534 }
10535
10536 /* 66 0F 63 = PACKSSWB */
10537 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
10538 delta = dis_SSEint_E_to_G( sorb, delta+2,
sewardjc9bff7d2011-06-15 15:09:37 +000010539 "packsswb",
sewardj5f438dd2011-06-16 11:36:23 +000010540 Iop_QNarrowBin16Sto8Sx16, True );
sewardj164f9272004-12-09 00:39:32 +000010541 goto decode_success;
10542 }
10543
10544 /* 66 0F 67 = PACKUSWB */
10545 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
10546 delta = dis_SSEint_E_to_G( sorb, delta+2,
sewardjc9bff7d2011-06-15 15:09:37 +000010547 "packuswb",
sewardj5f438dd2011-06-16 11:36:23 +000010548 Iop_QNarrowBin16Sto8Ux16, True );
sewardj164f9272004-12-09 00:39:32 +000010549 goto decode_success;
10550 }
10551
10552 /* 66 0F FC = PADDB */
10553 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
10554 delta = dis_SSEint_E_to_G( sorb, delta+2,
10555 "paddb", Iop_Add8x16, False );
10556 goto decode_success;
10557 }
10558
10559 /* 66 0F FE = PADDD */
10560 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
10561 delta = dis_SSEint_E_to_G( sorb, delta+2,
10562 "paddd", Iop_Add32x4, False );
10563 goto decode_success;
10564 }
10565
10566 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10567 /* 0F D4 = PADDQ -- add 64x1 */
10568 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
10569 do_MMX_preamble();
10570 delta = dis_MMXop_regmem_to_reg (
10571 sorb, delta+2, insn[1], "paddq", False );
10572 goto decode_success;
10573 }
10574
10575 /* 66 0F D4 = PADDQ */
10576 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
10577 delta = dis_SSEint_E_to_G( sorb, delta+2,
10578 "paddq", Iop_Add64x2, False );
10579 goto decode_success;
10580 }
10581
10582 /* 66 0F FD = PADDW */
10583 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
10584 delta = dis_SSEint_E_to_G( sorb, delta+2,
10585 "paddw", Iop_Add16x8, False );
10586 goto decode_success;
10587 }
10588
10589 /* 66 0F EC = PADDSB */
10590 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
10591 delta = dis_SSEint_E_to_G( sorb, delta+2,
10592 "paddsb", Iop_QAdd8Sx16, False );
10593 goto decode_success;
10594 }
10595
10596 /* 66 0F ED = PADDSW */
10597 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
10598 delta = dis_SSEint_E_to_G( sorb, delta+2,
10599 "paddsw", Iop_QAdd16Sx8, False );
10600 goto decode_success;
10601 }
10602
10603 /* 66 0F DC = PADDUSB */
10604 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
10605 delta = dis_SSEint_E_to_G( sorb, delta+2,
10606 "paddusb", Iop_QAdd8Ux16, False );
10607 goto decode_success;
10608 }
10609
10610 /* 66 0F DD = PADDUSW */
10611 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
10612 delta = dis_SSEint_E_to_G( sorb, delta+2,
10613 "paddusw", Iop_QAdd16Ux8, False );
10614 goto decode_success;
10615 }
10616
10617 /* 66 0F DB = PAND */
10618 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
sewardjf0c1c582005-02-07 23:47:38 +000010619 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +000010620 goto decode_success;
10621 }
10622
10623 /* 66 0F DF = PANDN */
10624 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
sewardjf0c1c582005-02-07 23:47:38 +000010625 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +000010626 goto decode_success;
10627 }
10628
10629 /* 66 0F E0 = PAVGB */
10630 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
10631 delta = dis_SSEint_E_to_G( sorb, delta+2,
10632 "pavgb", Iop_Avg8Ux16, False );
10633 goto decode_success;
10634 }
10635
10636 /* 66 0F E3 = PAVGW */
10637 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
10638 delta = dis_SSEint_E_to_G( sorb, delta+2,
10639 "pavgw", Iop_Avg16Ux8, False );
10640 goto decode_success;
10641 }
10642
sewardje5854d62004-12-09 03:44:34 +000010643 /* 66 0F 74 = PCMPEQB */
10644 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
10645 delta = dis_SSEint_E_to_G( sorb, delta+2,
10646 "pcmpeqb", Iop_CmpEQ8x16, False );
10647 goto decode_success;
10648 }
10649
10650 /* 66 0F 76 = PCMPEQD */
10651 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
10652 delta = dis_SSEint_E_to_G( sorb, delta+2,
10653 "pcmpeqd", Iop_CmpEQ32x4, False );
10654 goto decode_success;
10655 }
10656
10657 /* 66 0F 75 = PCMPEQW */
10658 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
10659 delta = dis_SSEint_E_to_G( sorb, delta+2,
10660 "pcmpeqw", Iop_CmpEQ16x8, False );
10661 goto decode_success;
10662 }
10663
10664 /* 66 0F 64 = PCMPGTB */
10665 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
10666 delta = dis_SSEint_E_to_G( sorb, delta+2,
10667 "pcmpgtb", Iop_CmpGT8Sx16, False );
10668 goto decode_success;
10669 }
10670
10671 /* 66 0F 66 = PCMPGTD */
10672 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
10673 delta = dis_SSEint_E_to_G( sorb, delta+2,
10674 "pcmpgtd", Iop_CmpGT32Sx4, False );
10675 goto decode_success;
10676 }
10677
10678 /* 66 0F 65 = PCMPGTW */
10679 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
10680 delta = dis_SSEint_E_to_G( sorb, delta+2,
10681 "pcmpgtw", Iop_CmpGT16Sx8, False );
10682 goto decode_success;
10683 }
10684
10685 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10686 zero-extend of it in ireg(G). */
10687 if (insn[0] == 0x0F && insn[1] == 0xC5) {
10688 modrm = insn[2];
10689 if (sz == 2 && epartIsReg(modrm)) {
10690 t5 = newTemp(Ity_V128);
10691 t4 = newTemp(Ity_I16);
10692 assign(t5, getXMMReg(eregOfRM(modrm)));
10693 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10694 switch (insn[3] & 7) {
10695 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
10696 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
10697 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
10698 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
10699 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
10700 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
10701 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
10702 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
sewardjba89f4c2005-04-07 17:31:27 +000010703 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +000010704 }
10705 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
10706 DIP("pextrw $%d,%s,%s\n",
10707 (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
10708 nameIReg(4,gregOfRM(modrm)));
10709 delta += 4;
10710 goto decode_success;
10711 }
10712 /* else fall through */
10713 }
10714
10715 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
10716 put it into the specified lane of xmm(G). */
10717 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
10718 Int lane;
10719 t4 = newTemp(Ity_I16);
10720 modrm = insn[2];
10721
10722 if (epartIsReg(modrm)) {
10723 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +000010724 delta += 3+1;
10725 lane = insn[3+1-1];
sewardje5854d62004-12-09 03:44:34 +000010726 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10727 nameIReg(2,eregOfRM(modrm)),
10728 nameXMMReg(gregOfRM(modrm)));
10729 } else {
sewardjaac7e082005-03-17 14:03:46 +000010730 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10731 delta += 3+alen;
10732 lane = insn[3+alen-1];
10733 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
10734 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10735 dis_buf,
10736 nameXMMReg(gregOfRM(modrm)));
sewardje5854d62004-12-09 03:44:34 +000010737 }
10738
10739 putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
10740 goto decode_success;
10741 }
10742
sewardjb8a3dea2005-10-04 20:00:49 +000010743 /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
10744 E(xmm or mem) to G(xmm) */
10745 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF5) {
10746 IRTemp s1V = newTemp(Ity_V128);
10747 IRTemp s2V = newTemp(Ity_V128);
10748 IRTemp dV = newTemp(Ity_V128);
10749 IRTemp s1Hi = newTemp(Ity_I64);
10750 IRTemp s1Lo = newTemp(Ity_I64);
10751 IRTemp s2Hi = newTemp(Ity_I64);
10752 IRTemp s2Lo = newTemp(Ity_I64);
10753 IRTemp dHi = newTemp(Ity_I64);
10754 IRTemp dLo = newTemp(Ity_I64);
10755 modrm = insn[2];
10756 if (epartIsReg(modrm)) {
10757 assign( s1V, getXMMReg(eregOfRM(modrm)) );
10758 delta += 2+1;
10759 DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10760 nameXMMReg(gregOfRM(modrm)));
10761 } else {
10762 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10763 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
10764 delta += 2+alen;
10765 DIP("pmaddwd %s,%s\n", dis_buf,
10766 nameXMMReg(gregOfRM(modrm)));
10767 }
10768 assign( s2V, getXMMReg(gregOfRM(modrm)) );
10769 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
10770 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
10771 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
10772 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
10773 assign( dHi, mkIRExprCCall(
10774 Ity_I64, 0/*regparms*/,
10775 "x86g_calculate_mmx_pmaddwd",
10776 &x86g_calculate_mmx_pmaddwd,
10777 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
10778 ));
10779 assign( dLo, mkIRExprCCall(
10780 Ity_I64, 0/*regparms*/,
10781 "x86g_calculate_mmx_pmaddwd",
10782 &x86g_calculate_mmx_pmaddwd,
10783 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
10784 ));
10785 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
10786 putXMMReg(gregOfRM(modrm), mkexpr(dV));
10787 goto decode_success;
10788 }
10789
sewardje5854d62004-12-09 03:44:34 +000010790 /* 66 0F EE = PMAXSW -- 16x8 signed max */
10791 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
10792 delta = dis_SSEint_E_to_G( sorb, delta+2,
10793 "pmaxsw", Iop_Max16Sx8, False );
10794 goto decode_success;
10795 }
10796
10797 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
10798 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
10799 delta = dis_SSEint_E_to_G( sorb, delta+2,
10800 "pmaxub", Iop_Max8Ux16, False );
10801 goto decode_success;
10802 }
10803
10804 /* 66 0F EA = PMINSW -- 16x8 signed min */
10805 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
10806 delta = dis_SSEint_E_to_G( sorb, delta+2,
10807 "pminsw", Iop_Min16Sx8, False );
10808 goto decode_success;
10809 }
10810
10811 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
10812 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
10813 delta = dis_SSEint_E_to_G( sorb, delta+2,
10814 "pminub", Iop_Min8Ux16, False );
10815 goto decode_success;
10816 }
10817
10818 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
10819 xmm(G), turn them into a byte, and put zero-extend of it in
10820 ireg(G). Doing this directly is just too cumbersome; give up
10821 therefore and call a helper. */
10822 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
10823 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
10824 modrm = insn[2];
10825 if (epartIsReg(modrm)) {
10826 t0 = newTemp(Ity_I64);
10827 t1 = newTemp(Ity_I64);
10828 assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
10829 assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
10830 t5 = newTemp(Ity_I32);
10831 assign(t5, mkIRExprCCall(
10832 Ity_I32, 0/*regparms*/,
10833 "x86g_calculate_sse_pmovmskb",
10834 &x86g_calculate_sse_pmovmskb,
sewardj28e5c832004-12-16 11:39:04 +000010835 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
sewardje5854d62004-12-09 03:44:34 +000010836 putIReg(4, gregOfRM(modrm), mkexpr(t5));
10837 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10838 nameIReg(4,gregOfRM(modrm)));
10839 delta += 3;
10840 goto decode_success;
10841 }
10842 /* else fall through */
10843 }
10844
10845 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
10846 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
10847 delta = dis_SSEint_E_to_G( sorb, delta+2,
10848 "pmulhuw", Iop_MulHi16Ux8, False );
10849 goto decode_success;
10850 }
10851
10852 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
10853 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
10854 delta = dis_SSEint_E_to_G( sorb, delta+2,
10855 "pmulhw", Iop_MulHi16Sx8, False );
10856 goto decode_success;
10857 }
10858
10859 /* 66 0F D5 = PMULHL -- 16x8 multiply */
10860 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
10861 delta = dis_SSEint_E_to_G( sorb, delta+2,
10862 "pmullw", Iop_Mul16x8, False );
10863 goto decode_success;
10864 }
10865
10866 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10867 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10868 0 to form 64-bit result */
10869 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
10870 IRTemp sV = newTemp(Ity_I64);
10871 IRTemp dV = newTemp(Ity_I64);
10872 t1 = newTemp(Ity_I32);
10873 t0 = newTemp(Ity_I32);
10874 modrm = insn[2];
10875
10876 do_MMX_preamble();
10877 assign( dV, getMMXReg(gregOfRM(modrm)) );
10878
10879 if (epartIsReg(modrm)) {
10880 assign( sV, getMMXReg(eregOfRM(modrm)) );
10881 delta += 2+1;
10882 DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10883 nameMMXReg(gregOfRM(modrm)));
10884 } else {
10885 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10886 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
10887 delta += 2+alen;
10888 DIP("pmuludq %s,%s\n", dis_buf,
10889 nameMMXReg(gregOfRM(modrm)));
10890 }
10891
10892 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
10893 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
10894 putMMXReg( gregOfRM(modrm),
10895 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
10896 goto decode_success;
10897 }
10898
10899 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10900 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
10901 half */
10902 /* This is a really poor translation -- could be improved if
10903 performance critical */
10904 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
10905 IRTemp sV, dV;
10906 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
10907 sV = newTemp(Ity_V128);
10908 dV = newTemp(Ity_V128);
10909 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
10910 t1 = newTemp(Ity_I64);
10911 t0 = newTemp(Ity_I64);
10912 modrm = insn[2];
10913 assign( dV, getXMMReg(gregOfRM(modrm)) );
10914
10915 if (epartIsReg(modrm)) {
10916 assign( sV, getXMMReg(eregOfRM(modrm)) );
10917 delta += 2+1;
10918 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10919 nameXMMReg(gregOfRM(modrm)));
10920 } else {
10921 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10922 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10923 delta += 2+alen;
10924 DIP("pmuludq %s,%s\n", dis_buf,
10925 nameXMMReg(gregOfRM(modrm)));
10926 }
10927
10928 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
10929 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10930
10931 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
10932 putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
10933 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
10934 putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
10935 goto decode_success;
10936 }
10937
10938 /* 66 0F EB = POR */
10939 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
sewardjf0c1c582005-02-07 23:47:38 +000010940 delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_OrV128 );
sewardje5854d62004-12-09 03:44:34 +000010941 goto decode_success;
10942 }
10943
sewardj7b5b9982005-10-04 11:43:37 +000010944 /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
10945 from E(xmm or mem) to G(xmm) */
10946 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF6) {
10947 IRTemp s1V = newTemp(Ity_V128);
10948 IRTemp s2V = newTemp(Ity_V128);
10949 IRTemp dV = newTemp(Ity_V128);
10950 IRTemp s1Hi = newTemp(Ity_I64);
10951 IRTemp s1Lo = newTemp(Ity_I64);
10952 IRTemp s2Hi = newTemp(Ity_I64);
10953 IRTemp s2Lo = newTemp(Ity_I64);
10954 IRTemp dHi = newTemp(Ity_I64);
10955 IRTemp dLo = newTemp(Ity_I64);
10956 modrm = insn[2];
10957 if (epartIsReg(modrm)) {
10958 assign( s1V, getXMMReg(eregOfRM(modrm)) );
10959 delta += 2+1;
10960 DIP("psadbw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10961 nameXMMReg(gregOfRM(modrm)));
10962 } else {
10963 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10964 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
10965 delta += 2+alen;
10966 DIP("psadbw %s,%s\n", dis_buf,
10967 nameXMMReg(gregOfRM(modrm)));
10968 }
10969 assign( s2V, getXMMReg(gregOfRM(modrm)) );
10970 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
10971 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
10972 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
10973 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
10974 assign( dHi, mkIRExprCCall(
10975 Ity_I64, 0/*regparms*/,
10976 "x86g_calculate_mmx_psadbw",
10977 &x86g_calculate_mmx_psadbw,
10978 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
10979 ));
10980 assign( dLo, mkIRExprCCall(
10981 Ity_I64, 0/*regparms*/,
10982 "x86g_calculate_mmx_psadbw",
10983 &x86g_calculate_mmx_psadbw,
10984 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
10985 ));
10986 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
10987 putXMMReg(gregOfRM(modrm), mkexpr(dV));
10988 goto decode_success;
10989 }
10990
sewardjb9fa69b2004-12-09 23:25:14 +000010991 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
10992 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
10993 Int order;
10994 IRTemp sV, dV, s3, s2, s1, s0;
10995 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10996 sV = newTemp(Ity_V128);
10997 dV = newTemp(Ity_V128);
10998 modrm = insn[2];
10999 if (epartIsReg(modrm)) {
11000 assign( sV, getXMMReg(eregOfRM(modrm)) );
11001 order = (Int)insn[3];
11002 delta += 2+2;
11003 DIP("pshufd $%d,%s,%s\n", order,
11004 nameXMMReg(eregOfRM(modrm)),
11005 nameXMMReg(gregOfRM(modrm)));
11006 } else {
11007 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11008 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11009 order = (Int)insn[2+alen];
11010 delta += 3+alen;
11011 DIP("pshufd $%d,%s,%s\n", order,
11012 dis_buf,
11013 nameXMMReg(gregOfRM(modrm)));
11014 }
11015 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11016
11017# define SEL(n) \
11018 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11019 assign(dV,
11020 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
11021 SEL((order>>2)&3), SEL((order>>0)&3) )
11022 );
11023 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11024# undef SEL
11025 goto decode_success;
11026 }
11027
11028 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
11029 mem) to G(xmm), and copy lower half */
11030 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
11031 Int order;
11032 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
11033 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11034 sV = newTemp(Ity_V128);
11035 dV = newTemp(Ity_V128);
11036 sVhi = newTemp(Ity_I64);
11037 dVhi = newTemp(Ity_I64);
11038 modrm = insn[3];
11039 if (epartIsReg(modrm)) {
11040 assign( sV, getXMMReg(eregOfRM(modrm)) );
11041 order = (Int)insn[4];
11042 delta += 4+1;
11043 DIP("pshufhw $%d,%s,%s\n", order,
11044 nameXMMReg(eregOfRM(modrm)),
11045 nameXMMReg(gregOfRM(modrm)));
11046 } else {
11047 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11048 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11049 order = (Int)insn[3+alen];
11050 delta += 4+alen;
11051 DIP("pshufhw $%d,%s,%s\n", order,
11052 dis_buf,
11053 nameXMMReg(gregOfRM(modrm)));
11054 }
sewardjf0c1c582005-02-07 23:47:38 +000011055 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +000011056 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
11057
11058# define SEL(n) \
11059 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11060 assign(dVhi,
11061 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11062 SEL((order>>2)&3), SEL((order>>0)&3) )
11063 );
sewardjf0c1c582005-02-07 23:47:38 +000011064 assign(dV, binop( Iop_64HLtoV128,
sewardjb9fa69b2004-12-09 23:25:14 +000011065 mkexpr(dVhi),
sewardjf0c1c582005-02-07 23:47:38 +000011066 unop(Iop_V128to64, mkexpr(sV))) );
sewardjb9fa69b2004-12-09 23:25:14 +000011067 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11068# undef SEL
11069 goto decode_success;
11070 }
11071
11072 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
11073 mem) to G(xmm), and copy upper half */
11074 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
11075 Int order;
11076 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
11077 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11078 sV = newTemp(Ity_V128);
11079 dV = newTemp(Ity_V128);
11080 sVlo = newTemp(Ity_I64);
11081 dVlo = newTemp(Ity_I64);
11082 modrm = insn[3];
11083 if (epartIsReg(modrm)) {
11084 assign( sV, getXMMReg(eregOfRM(modrm)) );
11085 order = (Int)insn[4];
11086 delta += 4+1;
11087 DIP("pshuflw $%d,%s,%s\n", order,
11088 nameXMMReg(eregOfRM(modrm)),
11089 nameXMMReg(gregOfRM(modrm)));
11090 } else {
11091 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11092 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11093 order = (Int)insn[3+alen];
11094 delta += 4+alen;
11095 DIP("pshuflw $%d,%s,%s\n", order,
11096 dis_buf,
11097 nameXMMReg(gregOfRM(modrm)));
11098 }
sewardjf0c1c582005-02-07 23:47:38 +000011099 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +000011100 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
11101
11102# define SEL(n) \
11103 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11104 assign(dVlo,
11105 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11106 SEL((order>>2)&3), SEL((order>>0)&3) )
11107 );
sewardjf0c1c582005-02-07 23:47:38 +000011108 assign(dV, binop( Iop_64HLtoV128,
11109 unop(Iop_V128HIto64, mkexpr(sV)),
sewardjb9fa69b2004-12-09 23:25:14 +000011110 mkexpr(dVlo) ) );
11111 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11112# undef SEL
11113 goto decode_success;
11114 }
11115
11116 /* 66 0F 72 /6 ib = PSLLD by immediate */
11117 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11118 && epartIsReg(insn[2])
11119 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000011120 delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000011121 goto decode_success;
11122 }
11123
11124 /* 66 0F F2 = PSLLD by E */
11125 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
11126 delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
11127 goto decode_success;
11128 }
11129
sewardjb9fa69b2004-12-09 23:25:14 +000011130 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
11131 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11132 && epartIsReg(insn[2])
11133 && gregOfRM(insn[2]) == 7) {
sewardj0c9907c2005-01-10 20:37:31 +000011134 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11135 Int imm = (Int)insn[3];
11136 Int reg = eregOfRM(insn[2]);
11137 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
11138 vassert(imm >= 0 && imm <= 255);
11139 delta += 4;
11140
11141 sV = newTemp(Ity_V128);
11142 dV = newTemp(Ity_V128);
11143 hi64 = newTemp(Ity_I64);
11144 lo64 = newTemp(Ity_I64);
11145 hi64r = newTemp(Ity_I64);
11146 lo64r = newTemp(Ity_I64);
11147
11148 if (imm >= 16) {
sewardj0c9907c2005-01-10 20:37:31 +000011149 putXMMReg(reg, mkV128(0x0000));
11150 goto decode_success;
11151 }
11152
11153 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +000011154 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11155 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj0c9907c2005-01-10 20:37:31 +000011156
sewardjba89f4c2005-04-07 17:31:27 +000011157 if (imm == 0) {
11158 assign( lo64r, mkexpr(lo64) );
11159 assign( hi64r, mkexpr(hi64) );
11160 }
11161 else
sewardj0c9907c2005-01-10 20:37:31 +000011162 if (imm == 8) {
11163 assign( lo64r, mkU64(0) );
11164 assign( hi64r, mkexpr(lo64) );
11165 }
sewardjc02043c2005-01-11 15:03:53 +000011166 else
sewardj0c9907c2005-01-10 20:37:31 +000011167 if (imm > 8) {
sewardj0c9907c2005-01-10 20:37:31 +000011168 assign( lo64r, mkU64(0) );
11169 assign( hi64r, binop( Iop_Shl64,
11170 mkexpr(lo64),
11171 mkU8( 8*(imm-8) ) ));
11172 } else {
11173 assign( lo64r, binop( Iop_Shl64,
11174 mkexpr(lo64),
11175 mkU8(8 * imm) ));
11176 assign( hi64r,
11177 binop( Iop_Or64,
11178 binop(Iop_Shl64, mkexpr(hi64),
11179 mkU8(8 * imm)),
11180 binop(Iop_Shr64, mkexpr(lo64),
11181 mkU8(8 * (8 - imm)) )
11182 )
11183 );
11184 }
sewardjf0c1c582005-02-07 23:47:38 +000011185 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj0c9907c2005-01-10 20:37:31 +000011186 putXMMReg(reg, mkexpr(dV));
sewardjb9fa69b2004-12-09 23:25:14 +000011187 goto decode_success;
11188 }
sewardjb9fa69b2004-12-09 23:25:14 +000011189
11190 /* 66 0F 73 /6 ib = PSLLQ by immediate */
11191 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11192 && epartIsReg(insn[2])
11193 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000011194 delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +000011195 goto decode_success;
11196 }
11197
11198 /* 66 0F F3 = PSLLQ by E */
11199 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
11200 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
11201 goto decode_success;
11202 }
11203
11204 /* 66 0F 71 /6 ib = PSLLW by immediate */
11205 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11206 && epartIsReg(insn[2])
11207 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000011208 delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000011209 goto decode_success;
11210 }
11211
11212 /* 66 0F F1 = PSLLW by E */
11213 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
11214 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
11215 goto decode_success;
11216 }
11217
11218 /* 66 0F 72 /4 ib = PSRAD by immediate */
11219 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11220 && epartIsReg(insn[2])
11221 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +000011222 delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000011223 goto decode_success;
11224 }
11225
11226 /* 66 0F E2 = PSRAD by E */
11227 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
11228 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
11229 goto decode_success;
11230 }
11231
11232 /* 66 0F 71 /4 ib = PSRAW by immediate */
11233 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11234 && epartIsReg(insn[2])
11235 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +000011236 delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000011237 goto decode_success;
11238 }
11239
11240 /* 66 0F E1 = PSRAW by E */
11241 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
11242 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
11243 goto decode_success;
11244 }
11245
11246 /* 66 0F 72 /2 ib = PSRLD by immediate */
11247 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11248 && epartIsReg(insn[2])
11249 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000011250 delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000011251 goto decode_success;
11252 }
11253
11254 /* 66 0F D2 = PSRLD by E */
11255 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
11256 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
11257 goto decode_success;
11258 }
11259
sewardj9ee82862004-12-14 01:16:59 +000011260 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
11261 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11262 && epartIsReg(insn[2])
sewardj95535fe2004-12-15 17:42:58 +000011263 && gregOfRM(insn[2]) == 3) {
11264 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
sewardj9ee82862004-12-14 01:16:59 +000011265 Int imm = (Int)insn[3];
11266 Int reg = eregOfRM(insn[2]);
sewardj9ee82862004-12-14 01:16:59 +000011267 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
sewardj95535fe2004-12-15 17:42:58 +000011268 vassert(imm >= 0 && imm <= 255);
11269 delta += 4;
11270
11271 sV = newTemp(Ity_V128);
11272 dV = newTemp(Ity_V128);
11273 hi64 = newTemp(Ity_I64);
11274 lo64 = newTemp(Ity_I64);
11275 hi64r = newTemp(Ity_I64);
11276 lo64r = newTemp(Ity_I64);
11277
11278 if (imm >= 16) {
sewardj95535fe2004-12-15 17:42:58 +000011279 putXMMReg(reg, mkV128(0x0000));
11280 goto decode_success;
11281 }
11282
11283 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +000011284 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11285 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj95535fe2004-12-15 17:42:58 +000011286
sewardjba89f4c2005-04-07 17:31:27 +000011287 if (imm == 0) {
11288 assign( lo64r, mkexpr(lo64) );
11289 assign( hi64r, mkexpr(hi64) );
11290 }
11291 else
sewardj95535fe2004-12-15 17:42:58 +000011292 if (imm == 8) {
11293 assign( hi64r, mkU64(0) );
11294 assign( lo64r, mkexpr(hi64) );
11295 }
11296 else
11297 if (imm > 8) {
sewardj95535fe2004-12-15 17:42:58 +000011298 assign( hi64r, mkU64(0) );
11299 assign( lo64r, binop( Iop_Shr64,
11300 mkexpr(hi64),
11301 mkU8( 8*(imm-8) ) ));
11302 } else {
11303 assign( hi64r, binop( Iop_Shr64,
11304 mkexpr(hi64),
11305 mkU8(8 * imm) ));
11306 assign( lo64r,
11307 binop( Iop_Or64,
11308 binop(Iop_Shr64, mkexpr(lo64),
11309 mkU8(8 * imm)),
11310 binop(Iop_Shl64, mkexpr(hi64),
11311 mkU8(8 * (8 - imm)) )
11312 )
11313 );
11314 }
11315
sewardjf0c1c582005-02-07 23:47:38 +000011316 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj95535fe2004-12-15 17:42:58 +000011317 putXMMReg(reg, mkexpr(dV));
sewardj9ee82862004-12-14 01:16:59 +000011318 goto decode_success;
11319 }
11320
sewardjb9fa69b2004-12-09 23:25:14 +000011321 /* 66 0F 73 /2 ib = PSRLQ by immediate */
11322 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11323 && epartIsReg(insn[2])
11324 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000011325 delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +000011326 goto decode_success;
11327 }
11328
11329 /* 66 0F D3 = PSRLQ by E */
11330 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
11331 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
11332 goto decode_success;
11333 }
11334
11335 /* 66 0F 71 /2 ib = PSRLW by immediate */
11336 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11337 && epartIsReg(insn[2])
11338 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000011339 delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000011340 goto decode_success;
11341 }
11342
11343 /* 66 0F D1 = PSRLW by E */
11344 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
11345 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
11346 goto decode_success;
11347 }
11348
11349 /* 66 0F F8 = PSUBB */
11350 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
11351 delta = dis_SSEint_E_to_G( sorb, delta+2,
11352 "psubb", Iop_Sub8x16, False );
11353 goto decode_success;
11354 }
11355
11356 /* 66 0F FA = PSUBD */
11357 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
11358 delta = dis_SSEint_E_to_G( sorb, delta+2,
11359 "psubd", Iop_Sub32x4, False );
11360 goto decode_success;
11361 }
11362
11363 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11364 /* 0F FB = PSUBQ -- sub 64x1 */
11365 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
11366 do_MMX_preamble();
11367 delta = dis_MMXop_regmem_to_reg (
11368 sorb, delta+2, insn[1], "psubq", False );
11369 goto decode_success;
11370 }
11371
11372 /* 66 0F FB = PSUBQ */
11373 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
11374 delta = dis_SSEint_E_to_G( sorb, delta+2,
11375 "psubq", Iop_Sub64x2, False );
11376 goto decode_success;
11377 }
11378
11379 /* 66 0F F9 = PSUBW */
11380 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
11381 delta = dis_SSEint_E_to_G( sorb, delta+2,
11382 "psubw", Iop_Sub16x8, False );
11383 goto decode_success;
11384 }
11385
11386 /* 66 0F E8 = PSUBSB */
11387 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
11388 delta = dis_SSEint_E_to_G( sorb, delta+2,
11389 "psubsb", Iop_QSub8Sx16, False );
11390 goto decode_success;
11391 }
11392
11393 /* 66 0F E9 = PSUBSW */
11394 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
11395 delta = dis_SSEint_E_to_G( sorb, delta+2,
11396 "psubsw", Iop_QSub16Sx8, False );
11397 goto decode_success;
11398 }
11399
11400 /* 66 0F D8 = PSUBSB */
11401 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
11402 delta = dis_SSEint_E_to_G( sorb, delta+2,
11403 "psubusb", Iop_QSub8Ux16, False );
11404 goto decode_success;
11405 }
11406
11407 /* 66 0F D9 = PSUBSW */
11408 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
11409 delta = dis_SSEint_E_to_G( sorb, delta+2,
11410 "psubusw", Iop_QSub16Ux8, False );
11411 goto decode_success;
11412 }
11413
sewardj9e203592004-12-10 01:48:18 +000011414 /* 66 0F 68 = PUNPCKHBW */
11415 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
11416 delta = dis_SSEint_E_to_G( sorb, delta+2,
11417 "punpckhbw",
11418 Iop_InterleaveHI8x16, True );
11419 goto decode_success;
11420 }
11421
11422 /* 66 0F 6A = PUNPCKHDQ */
11423 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
11424 delta = dis_SSEint_E_to_G( sorb, delta+2,
11425 "punpckhdq",
11426 Iop_InterleaveHI32x4, True );
11427 goto decode_success;
11428 }
11429
11430 /* 66 0F 6D = PUNPCKHQDQ */
11431 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
11432 delta = dis_SSEint_E_to_G( sorb, delta+2,
11433 "punpckhqdq",
11434 Iop_InterleaveHI64x2, True );
11435 goto decode_success;
11436 }
11437
11438 /* 66 0F 69 = PUNPCKHWD */
11439 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
11440 delta = dis_SSEint_E_to_G( sorb, delta+2,
11441 "punpckhwd",
11442 Iop_InterleaveHI16x8, True );
11443 goto decode_success;
11444 }
11445
11446 /* 66 0F 60 = PUNPCKLBW */
11447 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
11448 delta = dis_SSEint_E_to_G( sorb, delta+2,
11449 "punpcklbw",
11450 Iop_InterleaveLO8x16, True );
11451 goto decode_success;
11452 }
11453
11454 /* 66 0F 62 = PUNPCKLDQ */
11455 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
11456 delta = dis_SSEint_E_to_G( sorb, delta+2,
11457 "punpckldq",
11458 Iop_InterleaveLO32x4, True );
11459 goto decode_success;
11460 }
11461
11462 /* 66 0F 6C = PUNPCKLQDQ */
11463 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
11464 delta = dis_SSEint_E_to_G( sorb, delta+2,
11465 "punpcklqdq",
11466 Iop_InterleaveLO64x2, True );
11467 goto decode_success;
11468 }
11469
11470 /* 66 0F 61 = PUNPCKLWD */
11471 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
11472 delta = dis_SSEint_E_to_G( sorb, delta+2,
11473 "punpcklwd",
11474 Iop_InterleaveLO16x8, True );
11475 goto decode_success;
11476 }
11477
11478 /* 66 0F EF = PXOR */
11479 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
sewardjf0c1c582005-02-07 23:47:38 +000011480 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_XorV128 );
sewardj9e203592004-12-10 01:48:18 +000011481 goto decode_success;
11482 }
11483
sewardjc9a65702004-07-07 16:32:57 +000011484//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11485//-- if (insn[0] == 0x0F && insn[1] == 0xAE
11486//-- && (!epartIsReg(insn[2]))
11487//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11488//-- Bool store = gregOfRM(insn[2]) == 0;
11489//-- vg_assert(sz == 4);
11490//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11491//-- t1 = LOW24(pair);
11492//-- eip += 2+HI8(pair);
11493//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11494//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11495//-- Lit16, (UShort)insn[2],
11496//-- TempReg, t1 );
11497//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11498//-- goto decode_success;
11499//-- }
sewardjc9a65702004-07-07 16:32:57 +000011500
sewardjbfceb082005-11-15 11:16:30 +000011501 /* 0F AE /7 = CLFLUSH -- flush cache line */
11502 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
11503 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
11504
11505 /* This is something of a hack. We need to know the size of the
11506 cache line containing addr. Since we don't (easily), assume
11507 256 on the basis that no real cache would have a line that
11508 big. It's safe to invalidate more stuff than we need, just
11509 inefficient. */
11510 UInt lineszB = 256;
11511
11512 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11513 delta += 2+alen;
11514
11515 /* Round addr down to the start of the containing block. */
11516 stmt( IRStmt_Put(
11517 OFFB_TISTART,
11518 binop( Iop_And32,
11519 mkexpr(addr),
11520 mkU32( ~(lineszB-1) ))) );
11521
11522 stmt( IRStmt_Put(OFFB_TILEN, mkU32(lineszB) ) );
11523
sewardjdd40fdf2006-12-24 02:20:24 +000011524 irsb->jumpkind = Ijk_TInval;
11525 irsb->next = mkU32(guest_EIP_bbstart+delta);
sewardjbfceb082005-11-15 11:16:30 +000011526 dres.whatNext = Dis_StopHere;
11527
11528 DIP("clflush %s\n", dis_buf);
11529 goto decode_success;
11530 }
sewardjc9a65702004-07-07 16:32:57 +000011531
11532 /* ---------------------------------------------------- */
sewardj90e91ee2005-11-07 14:23:52 +000011533 /* --- end of the SSE2 decoder. --- */
11534 /* ---------------------------------------------------- */
11535
11536 /* ---------------------------------------------------- */
11537 /* --- start of the SSE3 decoder. --- */
11538 /* ---------------------------------------------------- */
11539
11540 /* Skip parts of the decoder which don't apply given the stated
11541 guest subarchitecture. */
sewardj5117ce12006-01-27 21:20:15 +000011542 /* if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE3)) */
11543 /* In fact this is highly bogus; we accept SSE3 insns even on a
11544 SSE2-only guest since they turn into IR which can be re-emitted
11545 successfully on an SSE2 host. */
11546 if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
11547 goto after_sse_decoders; /* no SSE3 capabilities */
sewardj90e91ee2005-11-07 14:23:52 +000011548
11549 insn = (UChar*)&guest_code[delta];
11550
11551 /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
11552 duplicating some lanes (2:2:0:0). */
11553 /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
11554 duplicating some lanes (3:3:1:1). */
11555 if (sz == 4 && insn[0] == 0xF3 && insn[1] == 0x0F
11556 && (insn[2] == 0x12 || insn[2] == 0x16)) {
11557 IRTemp s3, s2, s1, s0;
11558 IRTemp sV = newTemp(Ity_V128);
11559 Bool isH = insn[2] == 0x16;
11560 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11561
11562 modrm = insn[3];
11563 if (epartIsReg(modrm)) {
11564 assign( sV, getXMMReg( eregOfRM(modrm)) );
11565 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11566 nameXMMReg(eregOfRM(modrm)),
11567 nameXMMReg(gregOfRM(modrm)));
11568 delta += 3+1;
11569 } else {
11570 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +000011571 gen_SEGV_if_not_16_aligned( addr );
sewardj90e91ee2005-11-07 14:23:52 +000011572 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11573 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11574 dis_buf,
11575 nameXMMReg(gregOfRM(modrm)));
11576 delta += 3+alen;
11577 }
11578
11579 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11580 putXMMReg( gregOfRM(modrm),
11581 isH ? mk128from32s( s3, s3, s1, s1 )
11582 : mk128from32s( s2, s2, s0, s0 ) );
11583 goto decode_success;
11584 }
11585
sewardjdd5d2042006-08-03 15:03:19 +000011586 /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
11587 duplicating some lanes (0:1:0:1). */
11588 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x12) {
11589 IRTemp sV = newTemp(Ity_V128);
11590 IRTemp d0 = newTemp(Ity_I64);
11591
11592 modrm = insn[3];
11593 if (epartIsReg(modrm)) {
11594 assign( sV, getXMMReg( eregOfRM(modrm)) );
11595 DIP("movddup %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11596 nameXMMReg(gregOfRM(modrm)));
11597 delta += 3+1;
11598 assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
11599 } else {
11600 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11601 assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
11602 DIP("movddup %s,%s\n", dis_buf,
11603 nameXMMReg(gregOfRM(modrm)));
11604 delta += 3+alen;
11605 }
11606
11607 putXMMReg( gregOfRM(modrm), binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
11608 goto decode_success;
11609 }
11610
sewardj90e91ee2005-11-07 14:23:52 +000011611 /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
11612 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD0) {
11613 IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
11614 IRTemp eV = newTemp(Ity_V128);
11615 IRTemp gV = newTemp(Ity_V128);
11616 IRTemp addV = newTemp(Ity_V128);
11617 IRTemp subV = newTemp(Ity_V128);
11618 a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
11619
11620 modrm = insn[3];
11621 if (epartIsReg(modrm)) {
11622 assign( eV, getXMMReg( eregOfRM(modrm)) );
11623 DIP("addsubps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11624 nameXMMReg(gregOfRM(modrm)));
11625 delta += 3+1;
11626 } else {
11627 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11628 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11629 DIP("addsubps %s,%s\n", dis_buf,
11630 nameXMMReg(gregOfRM(modrm)));
11631 delta += 3+alen;
11632 }
11633
11634 assign( gV, getXMMReg(gregOfRM(modrm)) );
11635
11636 assign( addV, binop(Iop_Add32Fx4, mkexpr(gV), mkexpr(eV)) );
11637 assign( subV, binop(Iop_Sub32Fx4, mkexpr(gV), mkexpr(eV)) );
11638
11639 breakup128to32s( addV, &a3, &a2, &a1, &a0 );
11640 breakup128to32s( subV, &s3, &s2, &s1, &s0 );
11641
11642 putXMMReg( gregOfRM(modrm), mk128from32s( a3, s2, a1, s0 ));
11643 goto decode_success;
11644 }
11645
sewardjdd5d2042006-08-03 15:03:19 +000011646 /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
11647 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD0) {
11648 IRTemp eV = newTemp(Ity_V128);
11649 IRTemp gV = newTemp(Ity_V128);
11650 IRTemp addV = newTemp(Ity_V128);
11651 IRTemp subV = newTemp(Ity_V128);
11652 IRTemp a1 = newTemp(Ity_I64);
11653 IRTemp s0 = newTemp(Ity_I64);
11654
11655 modrm = insn[2];
11656 if (epartIsReg(modrm)) {
11657 assign( eV, getXMMReg( eregOfRM(modrm)) );
11658 DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11659 nameXMMReg(gregOfRM(modrm)));
11660 delta += 2+1;
11661 } else {
11662 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11663 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11664 DIP("addsubpd %s,%s\n", dis_buf,
11665 nameXMMReg(gregOfRM(modrm)));
11666 delta += 2+alen;
11667 }
11668
11669 assign( gV, getXMMReg(gregOfRM(modrm)) );
11670
11671 assign( addV, binop(Iop_Add64Fx2, mkexpr(gV), mkexpr(eV)) );
11672 assign( subV, binop(Iop_Sub64Fx2, mkexpr(gV), mkexpr(eV)) );
11673
11674 assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
11675 assign( s0, unop(Iop_V128to64, mkexpr(subV) ));
11676
11677 putXMMReg( gregOfRM(modrm),
11678 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
11679 goto decode_success;
11680 }
11681
11682 /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
11683 /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
11684 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F
11685 && (insn[2] == 0x7C || insn[2] == 0x7D)) {
11686 IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
11687 IRTemp eV = newTemp(Ity_V128);
11688 IRTemp gV = newTemp(Ity_V128);
11689 IRTemp leftV = newTemp(Ity_V128);
11690 IRTemp rightV = newTemp(Ity_V128);
11691 Bool isAdd = insn[2] == 0x7C;
11692 HChar* str = isAdd ? "add" : "sub";
11693 e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
11694
11695 modrm = insn[3];
11696 if (epartIsReg(modrm)) {
11697 assign( eV, getXMMReg( eregOfRM(modrm)) );
11698 DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11699 nameXMMReg(gregOfRM(modrm)));
11700 delta += 3+1;
11701 } else {
11702 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11703 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11704 DIP("h%sps %s,%s\n", str, dis_buf,
11705 nameXMMReg(gregOfRM(modrm)));
11706 delta += 3+alen;
11707 }
11708
11709 assign( gV, getXMMReg(gregOfRM(modrm)) );
11710
11711 breakup128to32s( eV, &e3, &e2, &e1, &e0 );
11712 breakup128to32s( gV, &g3, &g2, &g1, &g0 );
11713
11714 assign( leftV, mk128from32s( e2, e0, g2, g0 ) );
11715 assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
11716
11717 putXMMReg( gregOfRM(modrm),
11718 binop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
11719 mkexpr(leftV), mkexpr(rightV) ) );
11720 goto decode_success;
11721 }
11722
11723 /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
11724 /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
11725 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
11726 IRTemp e1 = newTemp(Ity_I64);
11727 IRTemp e0 = newTemp(Ity_I64);
11728 IRTemp g1 = newTemp(Ity_I64);
11729 IRTemp g0 = newTemp(Ity_I64);
11730 IRTemp eV = newTemp(Ity_V128);
11731 IRTemp gV = newTemp(Ity_V128);
11732 IRTemp leftV = newTemp(Ity_V128);
11733 IRTemp rightV = newTemp(Ity_V128);
11734 Bool isAdd = insn[1] == 0x7C;
11735 HChar* str = isAdd ? "add" : "sub";
11736
11737 modrm = insn[2];
11738 if (epartIsReg(modrm)) {
11739 assign( eV, getXMMReg( eregOfRM(modrm)) );
11740 DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11741 nameXMMReg(gregOfRM(modrm)));
11742 delta += 2+1;
11743 } else {
11744 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11745 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11746 DIP("h%spd %s,%s\n", str, dis_buf,
11747 nameXMMReg(gregOfRM(modrm)));
11748 delta += 2+alen;
11749 }
11750
11751 assign( gV, getXMMReg(gregOfRM(modrm)) );
11752
11753 assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
11754 assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
11755 assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
11756 assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
11757
11758 assign( leftV, binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
11759 assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
11760
11761 putXMMReg( gregOfRM(modrm),
11762 binop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
11763 mkexpr(leftV), mkexpr(rightV) ) );
11764 goto decode_success;
11765 }
11766
11767 /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
11768 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xF0) {
11769 modrm = getIByte(delta+3);
11770 if (epartIsReg(modrm)) {
11771 goto decode_failure;
11772 } else {
11773 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11774 putXMMReg( gregOfRM(modrm),
11775 loadLE(Ity_V128, mkexpr(addr)) );
11776 DIP("lddqu %s,%s\n", dis_buf,
11777 nameXMMReg(gregOfRM(modrm)));
11778 delta += 3+alen;
11779 }
11780 goto decode_success;
11781 }
11782
sewardj90e91ee2005-11-07 14:23:52 +000011783 /* ---------------------------------------------------- */
11784 /* --- end of the SSE3 decoder. --- */
sewardjc9a65702004-07-07 16:32:57 +000011785 /* ---------------------------------------------------- */
11786
sewardj150c9cd2008-02-09 01:16:02 +000011787 /* ---------------------------------------------------- */
11788 /* --- start of the SSSE3 decoder. --- */
11789 /* ---------------------------------------------------- */
11790
11791 /* 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
11792 Unsigned Bytes (MMX) */
11793 if (sz == 4
11794 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
11795 IRTemp sV = newTemp(Ity_I64);
11796 IRTemp dV = newTemp(Ity_I64);
11797 IRTemp sVoddsSX = newTemp(Ity_I64);
11798 IRTemp sVevensSX = newTemp(Ity_I64);
11799 IRTemp dVoddsZX = newTemp(Ity_I64);
11800 IRTemp dVevensZX = newTemp(Ity_I64);
11801
11802 modrm = insn[3];
11803 do_MMX_preamble();
11804 assign( dV, getMMXReg(gregOfRM(modrm)) );
11805
11806 if (epartIsReg(modrm)) {
11807 assign( sV, getMMXReg(eregOfRM(modrm)) );
11808 delta += 3+1;
11809 DIP("pmaddubsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
11810 nameMMXReg(gregOfRM(modrm)));
11811 } else {
11812 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11813 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11814 delta += 3+alen;
11815 DIP("pmaddubsw %s,%s\n", dis_buf,
11816 nameMMXReg(gregOfRM(modrm)));
11817 }
11818
11819 /* compute dV unsigned x sV signed */
11820 assign( sVoddsSX,
11821 binop(Iop_SarN16x4, mkexpr(sV), mkU8(8)) );
11822 assign( sVevensSX,
11823 binop(Iop_SarN16x4,
11824 binop(Iop_ShlN16x4, mkexpr(sV), mkU8(8)),
11825 mkU8(8)) );
11826 assign( dVoddsZX,
11827 binop(Iop_ShrN16x4, mkexpr(dV), mkU8(8)) );
11828 assign( dVevensZX,
11829 binop(Iop_ShrN16x4,
11830 binop(Iop_ShlN16x4, mkexpr(dV), mkU8(8)),
11831 mkU8(8)) );
11832
11833 putMMXReg(
11834 gregOfRM(modrm),
11835 binop(Iop_QAdd16Sx4,
11836 binop(Iop_Mul16x4, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
11837 binop(Iop_Mul16x4, mkexpr(sVevensSX), mkexpr(dVevensZX))
11838 )
11839 );
11840 goto decode_success;
11841 }
11842
11843 /* 66 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
11844 Unsigned Bytes (XMM) */
11845 if (sz == 2
11846 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
11847 IRTemp sV = newTemp(Ity_V128);
11848 IRTemp dV = newTemp(Ity_V128);
11849 IRTemp sVoddsSX = newTemp(Ity_V128);
11850 IRTemp sVevensSX = newTemp(Ity_V128);
11851 IRTemp dVoddsZX = newTemp(Ity_V128);
11852 IRTemp dVevensZX = newTemp(Ity_V128);
11853
11854 modrm = insn[3];
11855 assign( dV, getXMMReg(gregOfRM(modrm)) );
11856
11857 if (epartIsReg(modrm)) {
11858 assign( sV, getXMMReg(eregOfRM(modrm)) );
11859 delta += 3+1;
11860 DIP("pmaddubsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11861 nameXMMReg(gregOfRM(modrm)));
11862 } else {
11863 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11864 gen_SEGV_if_not_16_aligned( addr );
11865 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11866 delta += 3+alen;
11867 DIP("pmaddubsw %s,%s\n", dis_buf,
11868 nameXMMReg(gregOfRM(modrm)));
11869 }
11870
11871 /* compute dV unsigned x sV signed */
11872 assign( sVoddsSX,
11873 binop(Iop_SarN16x8, mkexpr(sV), mkU8(8)) );
11874 assign( sVevensSX,
11875 binop(Iop_SarN16x8,
11876 binop(Iop_ShlN16x8, mkexpr(sV), mkU8(8)),
11877 mkU8(8)) );
11878 assign( dVoddsZX,
11879 binop(Iop_ShrN16x8, mkexpr(dV), mkU8(8)) );
11880 assign( dVevensZX,
11881 binop(Iop_ShrN16x8,
11882 binop(Iop_ShlN16x8, mkexpr(dV), mkU8(8)),
11883 mkU8(8)) );
11884
11885 putXMMReg(
11886 gregOfRM(modrm),
11887 binop(Iop_QAdd16Sx8,
11888 binop(Iop_Mul16x8, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
11889 binop(Iop_Mul16x8, mkexpr(sVevensSX), mkexpr(dVevensZX))
11890 )
11891 );
11892 goto decode_success;
11893 }
11894
11895 /* ***--- these are MMX class insns introduced in SSSE3 ---*** */
11896 /* 0F 38 03 = PHADDSW -- 16x4 signed qadd across from E (mem or
11897 mmx) and G to G (mmx). */
11898 /* 0F 38 07 = PHSUBSW -- 16x4 signed qsub across from E (mem or
11899 mmx) and G to G (mmx). */
11900 /* 0F 38 01 = PHADDW -- 16x4 add across from E (mem or mmx) and G
11901 to G (mmx). */
11902 /* 0F 38 05 = PHSUBW -- 16x4 sub across from E (mem or mmx) and G
11903 to G (mmx). */
11904 /* 0F 38 02 = PHADDD -- 32x2 add across from E (mem or mmx) and G
11905 to G (mmx). */
11906 /* 0F 38 06 = PHSUBD -- 32x2 sub across from E (mem or mmx) and G
11907 to G (mmx). */
11908
11909 if (sz == 4
11910 && insn[0] == 0x0F && insn[1] == 0x38
11911 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
11912 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
11913 HChar* str = "???";
11914 IROp opV64 = Iop_INVALID;
11915 IROp opCatO = Iop_CatOddLanes16x4;
11916 IROp opCatE = Iop_CatEvenLanes16x4;
11917 IRTemp sV = newTemp(Ity_I64);
11918 IRTemp dV = newTemp(Ity_I64);
11919
11920 modrm = insn[3];
11921
11922 switch (insn[2]) {
11923 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
11924 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
11925 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
11926 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
11927 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
11928 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
11929 default: vassert(0);
11930 }
11931 if (insn[2] == 0x02 || insn[2] == 0x06) {
11932 opCatO = Iop_InterleaveHI32x2;
11933 opCatE = Iop_InterleaveLO32x2;
11934 }
11935
11936 do_MMX_preamble();
11937 assign( dV, getMMXReg(gregOfRM(modrm)) );
11938
11939 if (epartIsReg(modrm)) {
11940 assign( sV, getMMXReg(eregOfRM(modrm)) );
11941 delta += 3+1;
11942 DIP("ph%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
11943 nameMMXReg(gregOfRM(modrm)));
11944 } else {
11945 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11946 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11947 delta += 3+alen;
11948 DIP("ph%s %s,%s\n", str, dis_buf,
11949 nameMMXReg(gregOfRM(modrm)));
11950 }
11951
11952 putMMXReg(
11953 gregOfRM(modrm),
11954 binop(opV64,
11955 binop(opCatE,mkexpr(sV),mkexpr(dV)),
11956 binop(opCatO,mkexpr(sV),mkexpr(dV))
11957 )
11958 );
11959 goto decode_success;
11960 }
11961
11962 /* 66 0F 38 03 = PHADDSW -- 16x8 signed qadd across from E (mem or
11963 xmm) and G to G (xmm). */
11964 /* 66 0F 38 07 = PHSUBSW -- 16x8 signed qsub across from E (mem or
11965 xmm) and G to G (xmm). */
11966 /* 66 0F 38 01 = PHADDW -- 16x8 add across from E (mem or xmm) and
11967 G to G (xmm). */
11968 /* 66 0F 38 05 = PHSUBW -- 16x8 sub across from E (mem or xmm) and
11969 G to G (xmm). */
11970 /* 66 0F 38 02 = PHADDD -- 32x4 add across from E (mem or xmm) and
11971 G to G (xmm). */
11972 /* 66 0F 38 06 = PHSUBD -- 32x4 sub across from E (mem or xmm) and
11973 G to G (xmm). */
11974
11975 if (sz == 2
11976 && insn[0] == 0x0F && insn[1] == 0x38
11977 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
11978 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
11979 HChar* str = "???";
11980 IROp opV64 = Iop_INVALID;
11981 IROp opCatO = Iop_CatOddLanes16x4;
11982 IROp opCatE = Iop_CatEvenLanes16x4;
11983 IRTemp sV = newTemp(Ity_V128);
11984 IRTemp dV = newTemp(Ity_V128);
11985 IRTemp sHi = newTemp(Ity_I64);
11986 IRTemp sLo = newTemp(Ity_I64);
11987 IRTemp dHi = newTemp(Ity_I64);
11988 IRTemp dLo = newTemp(Ity_I64);
11989
11990 modrm = insn[3];
11991
11992 switch (insn[2]) {
11993 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
11994 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
11995 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
11996 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
11997 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
11998 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
11999 default: vassert(0);
12000 }
12001 if (insn[2] == 0x02 || insn[2] == 0x06) {
12002 opCatO = Iop_InterleaveHI32x2;
12003 opCatE = Iop_InterleaveLO32x2;
12004 }
12005
12006 assign( dV, getXMMReg(gregOfRM(modrm)) );
12007
12008 if (epartIsReg(modrm)) {
12009 assign( sV, getXMMReg( eregOfRM(modrm)) );
12010 DIP("ph%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12011 nameXMMReg(gregOfRM(modrm)));
12012 delta += 3+1;
12013 } else {
12014 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12015 gen_SEGV_if_not_16_aligned( addr );
12016 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12017 DIP("ph%s %s,%s\n", str, dis_buf,
12018 nameXMMReg(gregOfRM(modrm)));
12019 delta += 3+alen;
12020 }
12021
12022 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12023 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12024 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12025 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12026
12027 /* This isn't a particularly efficient way to compute the
12028 result, but at least it avoids a proliferation of IROps,
12029 hence avoids complication all the backends. */
12030 putXMMReg(
12031 gregOfRM(modrm),
12032 binop(Iop_64HLtoV128,
12033 binop(opV64,
12034 binop(opCatE,mkexpr(sHi),mkexpr(sLo)),
12035 binop(opCatO,mkexpr(sHi),mkexpr(sLo))
12036 ),
12037 binop(opV64,
12038 binop(opCatE,mkexpr(dHi),mkexpr(dLo)),
12039 binop(opCatO,mkexpr(dHi),mkexpr(dLo))
12040 )
12041 )
12042 );
12043 goto decode_success;
12044 }
12045
12046 /* 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and Scale
12047 (MMX) */
12048 if (sz == 4
12049 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12050 IRTemp sV = newTemp(Ity_I64);
12051 IRTemp dV = newTemp(Ity_I64);
12052
12053 modrm = insn[3];
12054 do_MMX_preamble();
12055 assign( dV, getMMXReg(gregOfRM(modrm)) );
12056
12057 if (epartIsReg(modrm)) {
12058 assign( sV, getMMXReg(eregOfRM(modrm)) );
12059 delta += 3+1;
12060 DIP("pmulhrsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12061 nameMMXReg(gregOfRM(modrm)));
12062 } else {
12063 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12064 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12065 delta += 3+alen;
12066 DIP("pmulhrsw %s,%s\n", dis_buf,
12067 nameMMXReg(gregOfRM(modrm)));
12068 }
12069
12070 putMMXReg(
12071 gregOfRM(modrm),
12072 dis_PMULHRSW_helper( mkexpr(sV), mkexpr(dV) )
12073 );
12074 goto decode_success;
12075 }
12076
12077 /* 66 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and
12078 Scale (XMM) */
12079 if (sz == 2
12080 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12081 IRTemp sV = newTemp(Ity_V128);
12082 IRTemp dV = newTemp(Ity_V128);
12083 IRTemp sHi = newTemp(Ity_I64);
12084 IRTemp sLo = newTemp(Ity_I64);
12085 IRTemp dHi = newTemp(Ity_I64);
12086 IRTemp dLo = newTemp(Ity_I64);
12087
12088 modrm = insn[3];
12089 assign( dV, getXMMReg(gregOfRM(modrm)) );
12090
12091 if (epartIsReg(modrm)) {
12092 assign( sV, getXMMReg(eregOfRM(modrm)) );
12093 delta += 3+1;
12094 DIP("pmulhrsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12095 nameXMMReg(gregOfRM(modrm)));
12096 } else {
12097 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12098 gen_SEGV_if_not_16_aligned( addr );
12099 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12100 delta += 3+alen;
12101 DIP("pmulhrsw %s,%s\n", dis_buf,
12102 nameXMMReg(gregOfRM(modrm)));
12103 }
12104
12105 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12106 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12107 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12108 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12109
12110 putXMMReg(
12111 gregOfRM(modrm),
12112 binop(Iop_64HLtoV128,
12113 dis_PMULHRSW_helper( mkexpr(sHi), mkexpr(dHi) ),
12114 dis_PMULHRSW_helper( mkexpr(sLo), mkexpr(dLo) )
12115 )
12116 );
12117 goto decode_success;
12118 }
12119
12120 /* 0F 38 08 = PSIGNB -- Packed Sign 8x8 (MMX) */
12121 /* 0F 38 09 = PSIGNW -- Packed Sign 16x4 (MMX) */
12122 /* 0F 38 09 = PSIGND -- Packed Sign 32x2 (MMX) */
12123 if (sz == 4
12124 && insn[0] == 0x0F && insn[1] == 0x38
12125 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12126 IRTemp sV = newTemp(Ity_I64);
12127 IRTemp dV = newTemp(Ity_I64);
12128 HChar* str = "???";
12129 Int laneszB = 0;
12130
12131 switch (insn[2]) {
12132 case 0x08: laneszB = 1; str = "b"; break;
12133 case 0x09: laneszB = 2; str = "w"; break;
12134 case 0x0A: laneszB = 4; str = "d"; break;
12135 default: vassert(0);
12136 }
12137
12138 modrm = insn[3];
12139 do_MMX_preamble();
12140 assign( dV, getMMXReg(gregOfRM(modrm)) );
12141
12142 if (epartIsReg(modrm)) {
12143 assign( sV, getMMXReg(eregOfRM(modrm)) );
12144 delta += 3+1;
12145 DIP("psign%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12146 nameMMXReg(gregOfRM(modrm)));
12147 } else {
12148 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12149 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12150 delta += 3+alen;
12151 DIP("psign%s %s,%s\n", str, dis_buf,
12152 nameMMXReg(gregOfRM(modrm)));
12153 }
12154
12155 putMMXReg(
12156 gregOfRM(modrm),
12157 dis_PSIGN_helper( mkexpr(sV), mkexpr(dV), laneszB )
12158 );
12159 goto decode_success;
12160 }
12161
12162 /* 66 0F 38 08 = PSIGNB -- Packed Sign 8x16 (XMM) */
12163 /* 66 0F 38 09 = PSIGNW -- Packed Sign 16x8 (XMM) */
12164 /* 66 0F 38 09 = PSIGND -- Packed Sign 32x4 (XMM) */
12165 if (sz == 2
12166 && insn[0] == 0x0F && insn[1] == 0x38
12167 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12168 IRTemp sV = newTemp(Ity_V128);
12169 IRTemp dV = newTemp(Ity_V128);
12170 IRTemp sHi = newTemp(Ity_I64);
12171 IRTemp sLo = newTemp(Ity_I64);
12172 IRTemp dHi = newTemp(Ity_I64);
12173 IRTemp dLo = newTemp(Ity_I64);
12174 HChar* str = "???";
12175 Int laneszB = 0;
12176
12177 switch (insn[2]) {
12178 case 0x08: laneszB = 1; str = "b"; break;
12179 case 0x09: laneszB = 2; str = "w"; break;
12180 case 0x0A: laneszB = 4; str = "d"; break;
12181 default: vassert(0);
12182 }
12183
12184 modrm = insn[3];
12185 assign( dV, getXMMReg(gregOfRM(modrm)) );
12186
12187 if (epartIsReg(modrm)) {
12188 assign( sV, getXMMReg(eregOfRM(modrm)) );
12189 delta += 3+1;
12190 DIP("psign%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12191 nameXMMReg(gregOfRM(modrm)));
12192 } else {
12193 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12194 gen_SEGV_if_not_16_aligned( addr );
12195 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12196 delta += 3+alen;
12197 DIP("psign%s %s,%s\n", str, dis_buf,
12198 nameXMMReg(gregOfRM(modrm)));
12199 }
12200
12201 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12202 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12203 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12204 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12205
12206 putXMMReg(
12207 gregOfRM(modrm),
12208 binop(Iop_64HLtoV128,
12209 dis_PSIGN_helper( mkexpr(sHi), mkexpr(dHi), laneszB ),
12210 dis_PSIGN_helper( mkexpr(sLo), mkexpr(dLo), laneszB )
12211 )
12212 );
12213 goto decode_success;
12214 }
12215
12216 /* 0F 38 1C = PABSB -- Packed Absolute Value 8x8 (MMX) */
12217 /* 0F 38 1D = PABSW -- Packed Absolute Value 16x4 (MMX) */
12218 /* 0F 38 1E = PABSD -- Packed Absolute Value 32x2 (MMX) */
12219 if (sz == 4
12220 && insn[0] == 0x0F && insn[1] == 0x38
12221 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12222 IRTemp sV = newTemp(Ity_I64);
12223 HChar* str = "???";
12224 Int laneszB = 0;
12225
12226 switch (insn[2]) {
12227 case 0x1C: laneszB = 1; str = "b"; break;
12228 case 0x1D: laneszB = 2; str = "w"; break;
12229 case 0x1E: laneszB = 4; str = "d"; break;
12230 default: vassert(0);
12231 }
12232
12233 modrm = insn[3];
12234 do_MMX_preamble();
12235
12236 if (epartIsReg(modrm)) {
12237 assign( sV, getMMXReg(eregOfRM(modrm)) );
12238 delta += 3+1;
12239 DIP("pabs%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12240 nameMMXReg(gregOfRM(modrm)));
12241 } else {
12242 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12243 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12244 delta += 3+alen;
12245 DIP("pabs%s %s,%s\n", str, dis_buf,
12246 nameMMXReg(gregOfRM(modrm)));
12247 }
12248
12249 putMMXReg(
12250 gregOfRM(modrm),
12251 dis_PABS_helper( mkexpr(sV), laneszB )
12252 );
12253 goto decode_success;
12254 }
12255
12256 /* 66 0F 38 1C = PABSB -- Packed Absolute Value 8x16 (XMM) */
12257 /* 66 0F 38 1D = PABSW -- Packed Absolute Value 16x8 (XMM) */
12258 /* 66 0F 38 1E = PABSD -- Packed Absolute Value 32x4 (XMM) */
12259 if (sz == 2
12260 && insn[0] == 0x0F && insn[1] == 0x38
12261 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12262 IRTemp sV = newTemp(Ity_V128);
12263 IRTemp sHi = newTemp(Ity_I64);
12264 IRTemp sLo = newTemp(Ity_I64);
12265 HChar* str = "???";
12266 Int laneszB = 0;
12267
12268 switch (insn[2]) {
12269 case 0x1C: laneszB = 1; str = "b"; break;
12270 case 0x1D: laneszB = 2; str = "w"; break;
12271 case 0x1E: laneszB = 4; str = "d"; break;
12272 default: vassert(0);
12273 }
12274
12275 modrm = insn[3];
12276
12277 if (epartIsReg(modrm)) {
12278 assign( sV, getXMMReg(eregOfRM(modrm)) );
12279 delta += 3+1;
12280 DIP("pabs%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12281 nameXMMReg(gregOfRM(modrm)));
12282 } else {
12283 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12284 gen_SEGV_if_not_16_aligned( addr );
12285 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12286 delta += 3+alen;
12287 DIP("pabs%s %s,%s\n", str, dis_buf,
12288 nameXMMReg(gregOfRM(modrm)));
12289 }
12290
12291 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12292 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12293
12294 putXMMReg(
12295 gregOfRM(modrm),
12296 binop(Iop_64HLtoV128,
12297 dis_PABS_helper( mkexpr(sHi), laneszB ),
12298 dis_PABS_helper( mkexpr(sLo), laneszB )
12299 )
12300 );
12301 goto decode_success;
12302 }
12303
12304 /* 0F 3A 0F = PALIGNR -- Packed Align Right (MMX) */
12305 if (sz == 4
12306 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12307 IRTemp sV = newTemp(Ity_I64);
12308 IRTemp dV = newTemp(Ity_I64);
12309 IRTemp res = newTemp(Ity_I64);
12310
12311 modrm = insn[3];
12312 do_MMX_preamble();
12313 assign( dV, getMMXReg(gregOfRM(modrm)) );
12314
12315 if (epartIsReg(modrm)) {
12316 assign( sV, getMMXReg(eregOfRM(modrm)) );
12317 d32 = (UInt)insn[3+1];
12318 delta += 3+1+1;
12319 DIP("palignr $%d,%s,%s\n", (Int)d32,
12320 nameMMXReg(eregOfRM(modrm)),
12321 nameMMXReg(gregOfRM(modrm)));
12322 } else {
12323 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12324 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12325 d32 = (UInt)insn[3+alen];
12326 delta += 3+alen+1;
12327 DIP("palignr $%d%s,%s\n", (Int)d32,
12328 dis_buf,
12329 nameMMXReg(gregOfRM(modrm)));
12330 }
12331
12332 if (d32 == 0) {
12333 assign( res, mkexpr(sV) );
12334 }
12335 else if (d32 >= 1 && d32 <= 7) {
12336 assign(res,
12337 binop(Iop_Or64,
12338 binop(Iop_Shr64, mkexpr(sV), mkU8(8*d32)),
12339 binop(Iop_Shl64, mkexpr(dV), mkU8(8*(8-d32))
12340 )));
12341 }
12342 else if (d32 == 8) {
12343 assign( res, mkexpr(dV) );
12344 }
12345 else if (d32 >= 9 && d32 <= 15) {
12346 assign( res, binop(Iop_Shr64, mkexpr(dV), mkU8(8*(d32-8))) );
12347 }
12348 else if (d32 >= 16 && d32 <= 255) {
12349 assign( res, mkU64(0) );
12350 }
12351 else
12352 vassert(0);
12353
12354 putMMXReg( gregOfRM(modrm), mkexpr(res) );
12355 goto decode_success;
12356 }
12357
12358 /* 66 0F 3A 0F = PALIGNR -- Packed Align Right (XMM) */
12359 if (sz == 2
12360 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12361 IRTemp sV = newTemp(Ity_V128);
12362 IRTemp dV = newTemp(Ity_V128);
12363 IRTemp sHi = newTemp(Ity_I64);
12364 IRTemp sLo = newTemp(Ity_I64);
12365 IRTemp dHi = newTemp(Ity_I64);
12366 IRTemp dLo = newTemp(Ity_I64);
12367 IRTemp rHi = newTemp(Ity_I64);
12368 IRTemp rLo = newTemp(Ity_I64);
12369
12370 modrm = insn[3];
12371 assign( dV, getXMMReg(gregOfRM(modrm)) );
12372
12373 if (epartIsReg(modrm)) {
12374 assign( sV, getXMMReg(eregOfRM(modrm)) );
12375 d32 = (UInt)insn[3+1];
12376 delta += 3+1+1;
12377 DIP("palignr $%d,%s,%s\n", (Int)d32,
12378 nameXMMReg(eregOfRM(modrm)),
12379 nameXMMReg(gregOfRM(modrm)));
12380 } else {
12381 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12382 gen_SEGV_if_not_16_aligned( addr );
12383 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12384 d32 = (UInt)insn[3+alen];
12385 delta += 3+alen+1;
12386 DIP("palignr $%d,%s,%s\n", (Int)d32,
12387 dis_buf,
12388 nameXMMReg(gregOfRM(modrm)));
12389 }
12390
12391 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12392 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12393 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12394 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12395
12396 if (d32 == 0) {
12397 assign( rHi, mkexpr(sHi) );
12398 assign( rLo, mkexpr(sLo) );
12399 }
12400 else if (d32 >= 1 && d32 <= 7) {
12401 assign( rHi, dis_PALIGNR_XMM_helper(dLo, sHi, d32) );
12402 assign( rLo, dis_PALIGNR_XMM_helper(sHi, sLo, d32) );
12403 }
12404 else if (d32 == 8) {
12405 assign( rHi, mkexpr(dLo) );
12406 assign( rLo, mkexpr(sHi) );
12407 }
12408 else if (d32 >= 9 && d32 <= 15) {
12409 assign( rHi, dis_PALIGNR_XMM_helper(dHi, dLo, d32-8) );
12410 assign( rLo, dis_PALIGNR_XMM_helper(dLo, sHi, d32-8) );
12411 }
12412 else if (d32 == 16) {
12413 assign( rHi, mkexpr(dHi) );
12414 assign( rLo, mkexpr(dLo) );
12415 }
12416 else if (d32 >= 17 && d32 <= 23) {
12417 assign( rHi, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-16))) );
12418 assign( rLo, dis_PALIGNR_XMM_helper(dHi, dLo, d32-16) );
12419 }
12420 else if (d32 == 24) {
12421 assign( rHi, mkU64(0) );
12422 assign( rLo, mkexpr(dHi) );
12423 }
12424 else if (d32 >= 25 && d32 <= 31) {
12425 assign( rHi, mkU64(0) );
12426 assign( rLo, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-24))) );
12427 }
12428 else if (d32 >= 32 && d32 <= 255) {
12429 assign( rHi, mkU64(0) );
12430 assign( rLo, mkU64(0) );
12431 }
12432 else
12433 vassert(0);
12434
12435 putXMMReg(
12436 gregOfRM(modrm),
12437 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12438 );
12439 goto decode_success;
12440 }
12441
12442 /* 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x8 (MMX) */
12443 if (sz == 4
12444 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12445 IRTemp sV = newTemp(Ity_I64);
12446 IRTemp dV = newTemp(Ity_I64);
12447
12448 modrm = insn[3];
12449 do_MMX_preamble();
12450 assign( dV, getMMXReg(gregOfRM(modrm)) );
12451
12452 if (epartIsReg(modrm)) {
12453 assign( sV, getMMXReg(eregOfRM(modrm)) );
12454 delta += 3+1;
12455 DIP("pshufb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12456 nameMMXReg(gregOfRM(modrm)));
12457 } else {
12458 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12459 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12460 delta += 3+alen;
12461 DIP("pshufb %s,%s\n", dis_buf,
12462 nameMMXReg(gregOfRM(modrm)));
12463 }
12464
12465 putMMXReg(
12466 gregOfRM(modrm),
12467 binop(
12468 Iop_And64,
12469 /* permute the lanes */
12470 binop(
12471 Iop_Perm8x8,
12472 mkexpr(dV),
12473 binop(Iop_And64, mkexpr(sV), mkU64(0x0707070707070707ULL))
12474 ),
12475 /* mask off lanes which have (index & 0x80) == 0x80 */
12476 unop(Iop_Not64, binop(Iop_SarN8x8, mkexpr(sV), mkU8(7)))
12477 )
12478 );
12479 goto decode_success;
12480 }
12481
12482 /* 66 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x16 (XMM) */
12483 if (sz == 2
12484 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12485 IRTemp sV = newTemp(Ity_V128);
12486 IRTemp dV = newTemp(Ity_V128);
12487 IRTemp sHi = newTemp(Ity_I64);
12488 IRTemp sLo = newTemp(Ity_I64);
12489 IRTemp dHi = newTemp(Ity_I64);
12490 IRTemp dLo = newTemp(Ity_I64);
12491 IRTemp rHi = newTemp(Ity_I64);
12492 IRTemp rLo = newTemp(Ity_I64);
12493 IRTemp sevens = newTemp(Ity_I64);
12494 IRTemp mask0x80hi = newTemp(Ity_I64);
12495 IRTemp mask0x80lo = newTemp(Ity_I64);
12496 IRTemp maskBit3hi = newTemp(Ity_I64);
12497 IRTemp maskBit3lo = newTemp(Ity_I64);
12498 IRTemp sAnd7hi = newTemp(Ity_I64);
12499 IRTemp sAnd7lo = newTemp(Ity_I64);
12500 IRTemp permdHi = newTemp(Ity_I64);
12501 IRTemp permdLo = newTemp(Ity_I64);
12502
12503 modrm = insn[3];
12504 assign( dV, getXMMReg(gregOfRM(modrm)) );
12505
12506 if (epartIsReg(modrm)) {
12507 assign( sV, getXMMReg(eregOfRM(modrm)) );
12508 delta += 3+1;
12509 DIP("pshufb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12510 nameXMMReg(gregOfRM(modrm)));
12511 } else {
12512 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12513 gen_SEGV_if_not_16_aligned( addr );
12514 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12515 delta += 3+alen;
12516 DIP("pshufb %s,%s\n", dis_buf,
12517 nameXMMReg(gregOfRM(modrm)));
12518 }
12519
12520 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12521 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12522 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12523 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12524
12525 assign( sevens, mkU64(0x0707070707070707ULL) );
12526
12527 /*
12528 mask0x80hi = Not(SarN8x8(sHi,7))
12529 maskBit3hi = SarN8x8(ShlN8x8(sHi,4),7)
12530 sAnd7hi = And(sHi,sevens)
12531 permdHi = Or( And(Perm8x8(dHi,sAnd7hi),maskBit3hi),
12532 And(Perm8x8(dLo,sAnd7hi),Not(maskBit3hi)) )
12533 rHi = And(permdHi,mask0x80hi)
12534 */
12535 assign(
12536 mask0x80hi,
12537 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sHi),mkU8(7))));
12538
12539 assign(
12540 maskBit3hi,
12541 binop(Iop_SarN8x8,
12542 binop(Iop_ShlN8x8,mkexpr(sHi),mkU8(4)),
12543 mkU8(7)));
12544
12545 assign(sAnd7hi, binop(Iop_And64,mkexpr(sHi),mkexpr(sevens)));
12546
12547 assign(
12548 permdHi,
12549 binop(
12550 Iop_Or64,
12551 binop(Iop_And64,
12552 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7hi)),
12553 mkexpr(maskBit3hi)),
12554 binop(Iop_And64,
12555 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7hi)),
12556 unop(Iop_Not64,mkexpr(maskBit3hi))) ));
12557
12558 assign(rHi, binop(Iop_And64,mkexpr(permdHi),mkexpr(mask0x80hi)) );
12559
12560 /* And the same for the lower half of the result. What fun. */
12561
12562 assign(
12563 mask0x80lo,
12564 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sLo),mkU8(7))));
12565
12566 assign(
12567 maskBit3lo,
12568 binop(Iop_SarN8x8,
12569 binop(Iop_ShlN8x8,mkexpr(sLo),mkU8(4)),
12570 mkU8(7)));
12571
12572 assign(sAnd7lo, binop(Iop_And64,mkexpr(sLo),mkexpr(sevens)));
12573
12574 assign(
12575 permdLo,
12576 binop(
12577 Iop_Or64,
12578 binop(Iop_And64,
12579 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7lo)),
12580 mkexpr(maskBit3lo)),
12581 binop(Iop_And64,
12582 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7lo)),
12583 unop(Iop_Not64,mkexpr(maskBit3lo))) ));
12584
12585 assign(rLo, binop(Iop_And64,mkexpr(permdLo),mkexpr(mask0x80lo)) );
12586
12587 putXMMReg(
12588 gregOfRM(modrm),
12589 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12590 );
12591 goto decode_success;
12592 }
12593
12594 /* ---------------------------------------------------- */
12595 /* --- end of the SSSE3 decoder. --- */
12596 /* ---------------------------------------------------- */
12597
sewardjb7271612010-07-23 21:23:25 +000012598 /* ---------------------------------------------------- */
12599 /* --- start of the SSE4 decoder --- */
12600 /* ---------------------------------------------------- */
12601
12602 /* 66 0F 3A 0B /r ib = ROUNDSD imm8, xmm2/m64, xmm1
12603 (Partial implementation only -- only deal with cases where
12604 the rounding mode is specified directly by the immediate byte.)
12605 66 0F 3A 0A /r ib = ROUNDSS imm8, xmm2/m32, xmm1
12606 (Limitations ditto)
12607 */
12608 if (sz == 2
12609 && insn[0] == 0x0F && insn[1] == 0x3A
12610 && (/*insn[2] == 0x0B || */insn[2] == 0x0A)) {
12611
12612 Bool isD = insn[2] == 0x0B;
12613 IRTemp src = newTemp(isD ? Ity_F64 : Ity_F32);
12614 IRTemp res = newTemp(isD ? Ity_F64 : Ity_F32);
12615 Int imm = 0;
12616
12617 modrm = insn[3];
12618
12619 if (epartIsReg(modrm)) {
12620 assign( src,
12621 isD ? getXMMRegLane64F( eregOfRM(modrm), 0 )
12622 : getXMMRegLane32F( eregOfRM(modrm), 0 ) );
12623 imm = insn[3+1];
12624 if (imm & ~3) goto decode_failure;
12625 delta += 3+1+1;
12626 DIP( "rounds%c $%d,%s,%s\n",
12627 isD ? 'd' : 's',
12628 imm, nameXMMReg( eregOfRM(modrm) ),
12629 nameXMMReg( gregOfRM(modrm) ) );
12630 } else {
12631 addr = disAMode( &alen, sorb, delta+3, dis_buf );
12632 assign( src, loadLE( isD ? Ity_F64 : Ity_F32, mkexpr(addr) ));
12633 imm = insn[3+alen];
12634 if (imm & ~3) goto decode_failure;
12635 delta += 3+alen+1;
12636 DIP( "roundsd $%d,%s,%s\n",
12637 imm, dis_buf, nameXMMReg( gregOfRM(modrm) ) );
12638 }
12639
12640 /* (imm & 3) contains an Intel-encoded rounding mode. Because
12641 that encoding is the same as the encoding for IRRoundingMode,
12642 we can use that value directly in the IR as a rounding
12643 mode. */
12644 assign(res, binop(isD ? Iop_RoundF64toInt : Iop_RoundF32toInt,
12645 mkU32(imm & 3), mkexpr(src)) );
12646
12647 if (isD)
12648 putXMMRegLane64F( gregOfRM(modrm), 0, mkexpr(res) );
12649 else
12650 putXMMRegLane32F( gregOfRM(modrm), 0, mkexpr(res) );
12651
12652 goto decode_success;
12653 }
12654
sewardj536fbab2010-07-29 15:39:05 +000012655 /* F3 0F BD -- LZCNT (count leading zeroes. An AMD extension,
12656 which we can only decode if we're sure this is an AMD cpu that
12657 supports LZCNT, since otherwise it's BSR, which behaves
12658 differently. */
12659 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xBD
12660 && 0 != (archinfo->hwcaps & VEX_HWCAPS_X86_LZCNT)) {
sewardj9a660ea2010-07-29 11:34:38 +000012661 vassert(sz == 2 || sz == 4);
12662 /*IRType*/ ty = szToITy(sz);
12663 IRTemp src = newTemp(ty);
12664 modrm = insn[3];
12665 if (epartIsReg(modrm)) {
12666 assign(src, getIReg(sz, eregOfRM(modrm)));
12667 delta += 3+1;
12668 DIP("lzcnt%c %s, %s\n", nameISize(sz),
12669 nameIReg(sz, eregOfRM(modrm)),
12670 nameIReg(sz, gregOfRM(modrm)));
12671 } else {
12672 addr = disAMode( &alen, sorb, delta+3, dis_buf );
12673 assign(src, loadLE(ty, mkexpr(addr)));
12674 delta += 3+alen;
12675 DIP("lzcnt%c %s, %s\n", nameISize(sz), dis_buf,
12676 nameIReg(sz, gregOfRM(modrm)));
12677 }
12678
12679 IRTemp res = gen_LZCNT(ty, src);
12680 putIReg(sz, gregOfRM(modrm), mkexpr(res));
12681
12682 // Update flags. This is pretty lame .. perhaps can do better
12683 // if this turns out to be performance critical.
12684 // O S A P are cleared. Z is set if RESULT == 0.
12685 // C is set if SRC is zero.
12686 IRTemp src32 = newTemp(Ity_I32);
12687 IRTemp res32 = newTemp(Ity_I32);
12688 assign(src32, widenUto32(mkexpr(src)));
12689 assign(res32, widenUto32(mkexpr(res)));
12690
12691 IRTemp oszacp = newTemp(Ity_I32);
12692 assign(
12693 oszacp,
12694 binop(Iop_Or32,
12695 binop(Iop_Shl32,
12696 unop(Iop_1Uto32,
12697 binop(Iop_CmpEQ32, mkexpr(res32), mkU32(0))),
12698 mkU8(X86G_CC_SHIFT_Z)),
12699 binop(Iop_Shl32,
12700 unop(Iop_1Uto32,
12701 binop(Iop_CmpEQ32, mkexpr(src32), mkU32(0))),
12702 mkU8(X86G_CC_SHIFT_C))
12703 )
12704 );
12705
12706 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
12707 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
12708 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
12709 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(oszacp) ));
12710
12711 goto decode_success;
12712 }
12713
sewardjb7271612010-07-23 21:23:25 +000012714 /* ---------------------------------------------------- */
12715 /* --- end of the SSE4 decoder --- */
12716 /* ---------------------------------------------------- */
12717
sewardj9df271d2004-12-31 22:37:42 +000012718 after_sse_decoders:
12719
sewardjdc5d0842006-11-16 10:42:02 +000012720 /* ---------------------------------------------------- */
12721 /* --- deal with misc 0x67 pfxs (addr size override) -- */
12722 /* ---------------------------------------------------- */
12723
12724 /* 67 E3 = JCXZ (for JECXZ see below) */
12725 if (insn[0] == 0x67 && insn[1] == 0xE3 && sz == 4) {
12726 delta += 2;
12727 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
12728 delta ++;
12729 stmt( IRStmt_Exit(
12730 binop(Iop_CmpEQ16, getIReg(2,R_ECX), mkU16(0)),
12731 Ijk_Boring,
12732 IRConst_U32(d32)
12733 ));
12734 DIP("jcxz 0x%x\n", d32);
12735 goto decode_success;
12736 }
12737
12738 /* ---------------------------------------------------- */
12739 /* --- start of the baseline insn decoder -- */
12740 /* ---------------------------------------------------- */
12741
sewardjc9a65702004-07-07 16:32:57 +000012742 /* Get the primary opcode. */
12743 opc = getIByte(delta); delta++;
12744
12745 /* We get here if the current insn isn't SSE, or this CPU doesn't
12746 support SSE. */
12747
12748 switch (opc) {
12749
12750 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +000012751
12752 case 0xC2: /* RET imm16 */
12753 d32 = getUDisp16(delta);
12754 delta += 2;
12755 dis_ret(d32);
sewardj9e6491a2005-07-02 19:24:10 +000012756 dres.whatNext = Dis_StopHere;
sewardj2d49b432005-02-01 00:37:06 +000012757 DIP("ret %d\n", (Int)d32);
sewardj940e8c92004-07-11 16:53:24 +000012758 break;
sewardje05c42c2004-07-08 20:25:10 +000012759 case 0xC3: /* RET */
12760 dis_ret(0);
sewardj9e6491a2005-07-02 19:24:10 +000012761 dres.whatNext = Dis_StopHere;
sewardje05c42c2004-07-08 20:25:10 +000012762 DIP("ret\n");
12763 break;
sewardj0e9a0f52008-01-04 01:22:41 +000012764
12765 case 0xCF: /* IRET */
12766 /* Note, this is an extremely kludgey and limited implementation
12767 of iret. All it really does is:
12768 popl %EIP; popl %CS; popl %EFLAGS.
12769 %CS is set but ignored (as it is in (eg) popw %cs)". */
12770 t1 = newTemp(Ity_I32); /* ESP */
12771 t2 = newTemp(Ity_I32); /* new EIP */
12772 t3 = newTemp(Ity_I32); /* new CS */
12773 t4 = newTemp(Ity_I32); /* new EFLAGS */
12774 assign(t1, getIReg(4,R_ESP));
12775 assign(t2, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(0) )));
12776 assign(t3, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(4) )));
12777 assign(t4, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(8) )));
12778 /* Get stuff off stack */
12779 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(12)));
12780 /* set %CS (which is ignored anyway) */
12781 putSReg( R_CS, unop(Iop_32to16, mkexpr(t3)) );
12782 /* set %EFLAGS */
12783 set_EFLAGS_from_value( t4, False/*!emit_AC_emwarn*/, 0/*unused*/ );
12784 /* goto new EIP value */
12785 jmp_treg(Ijk_Ret,t2);
12786 dres.whatNext = Dis_StopHere;
12787 DIP("iret (very kludgey)\n");
12788 break;
12789
sewardjd1061ab2004-07-08 01:45:30 +000012790 case 0xE8: /* CALL J4 */
12791 d32 = getUDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000012792 d32 += (guest_EIP_bbstart+delta);
sewardjce70a5c2004-10-18 14:09:54 +000012793 /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
sewardj9e6491a2005-07-02 19:24:10 +000012794 if (d32 == guest_EIP_bbstart+delta && getIByte(delta) >= 0x58
sewardjce70a5c2004-10-18 14:09:54 +000012795 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +000012796 /* Specially treat the position-independent-code idiom
12797 call X
12798 X: popl %reg
12799 as
12800 movl %eip, %reg.
12801 since this generates better code, but for no other reason. */
12802 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +000012803 /* vex_printf("-- fPIC thingy\n"); */
sewardj9e6491a2005-07-02 19:24:10 +000012804 putIReg(4, archReg, mkU32(guest_EIP_bbstart+delta));
sewardjd1061ab2004-07-08 01:45:30 +000012805 delta++; /* Step over the POP */
12806 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +000012807 } else {
sewardjd1061ab2004-07-08 01:45:30 +000012808 /* The normal sequence for a call. */
12809 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000012810 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
12811 putIReg(4, R_ESP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000012812 storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
sewardjc716aea2006-01-17 01:48:46 +000012813 if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32 )) {
sewardjce70a5c2004-10-18 14:09:54 +000012814 /* follow into the call target. */
sewardj984d9b12010-01-15 10:53:21 +000012815 dres.whatNext = Dis_ResteerU;
sewardj9e6491a2005-07-02 19:24:10 +000012816 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000012817 } else {
12818 jmp_lit(Ijk_Call,d32);
sewardj9e6491a2005-07-02 19:24:10 +000012819 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000012820 }
sewardjd1061ab2004-07-08 01:45:30 +000012821 DIP("call 0x%x\n",d32);
12822 }
12823 break;
12824
sewardjc9a65702004-07-07 16:32:57 +000012825//-- case 0xC8: /* ENTER */
12826//-- d32 = getUDisp16(eip); eip += 2;
12827//-- abyte = getIByte(delta); delta++;
12828//--
12829//-- vg_assert(sz == 4);
12830//-- vg_assert(abyte == 0);
12831//--
12832//-- t1 = newTemp(cb); t2 = newTemp(cb);
12833//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
12834//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
12835//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
12836//-- uLiteral(cb, sz);
12837//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
12838//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
12839//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
12840//-- if (d32) {
12841//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
sewardj5bd4d162004-11-10 13:02:48 +000012842//-- uLiteral(cb, d32);
12843//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
sewardjc9a65702004-07-07 16:32:57 +000012844//-- }
12845//-- DIP("enter 0x%x, 0x%x", d32, abyte);
12846//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +000012847
12848 case 0xC9: /* LEAVE */
12849 vassert(sz == 4);
12850 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
12851 assign(t1, getIReg(4,R_EBP));
12852 /* First PUT ESP looks redundant, but need it because ESP must
12853 always be up-to-date for Memcheck to work... */
12854 putIReg(4, R_ESP, mkexpr(t1));
12855 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
12856 putIReg(4, R_EBP, mkexpr(t2));
12857 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
12858 DIP("leave\n");
12859 break;
12860
sewardj8edc36b2007-11-23 02:46:29 +000012861 /* ---------------- Misc weird-ass insns --------------- */
12862
12863 case 0x27: /* DAA */
12864 case 0x2F: /* DAS */
12865 case 0x37: /* AAA */
12866 case 0x3F: /* AAS */
12867 /* An ugly implementation for some ugly instructions. Oh
12868 well. */
12869 if (sz != 4) goto decode_failure;
12870 t1 = newTemp(Ity_I32);
12871 t2 = newTemp(Ity_I32);
12872 /* Make up a 32-bit value (t1), with the old value of AX in the
12873 bottom 16 bits, and the old OSZACP bitmask in the upper 16
12874 bits. */
12875 assign(t1,
12876 binop(Iop_16HLto32,
12877 unop(Iop_32to16,
12878 mk_x86g_calculate_eflags_all()),
12879 getIReg(2, R_EAX)
12880 ));
12881 /* Call the helper fn, to get a new AX and OSZACP value, and
12882 poke both back into the guest state. Also pass the helper
12883 the actual opcode so it knows which of the 4 instructions it
12884 is doing the computation for. */
12885 vassert(opc == 0x27 || opc == 0x2F || opc == 0x37 || opc == 0x3F);
12886 assign(t2,
12887 mkIRExprCCall(
12888 Ity_I32, 0/*regparm*/, "x86g_calculate_daa_das_aaa_aas",
12889 &x86g_calculate_daa_das_aaa_aas,
12890 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
12891 ));
12892 putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
12893
12894 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
12895 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
12896 stmt( IRStmt_Put( OFFB_CC_DEP1,
12897 binop(Iop_And32,
12898 binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
12899 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
12900 | X86G_CC_MASK_A | X86G_CC_MASK_Z
12901 | X86G_CC_MASK_S| X86G_CC_MASK_O )
12902 )
12903 )
12904 );
12905 /* Set NDEP even though it isn't used. This makes redundant-PUT
12906 elimination of previous stores to this field work better. */
12907 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
12908 switch (opc) {
12909 case 0x27: DIP("daa\n"); break;
12910 case 0x2F: DIP("das\n"); break;
12911 case 0x37: DIP("aaa\n"); break;
12912 case 0x3F: DIP("aas\n"); break;
12913 default: vassert(0);
12914 }
12915 break;
12916
sewardj321bbbf2011-01-17 12:32:25 +000012917 case 0xD4: /* AAM */
12918 case 0xD5: /* AAD */
12919 d32 = getIByte(delta); delta++;
12920 if (sz != 4 || d32 != 10) goto decode_failure;
12921 t1 = newTemp(Ity_I32);
12922 t2 = newTemp(Ity_I32);
12923 /* Make up a 32-bit value (t1), with the old value of AX in the
12924 bottom 16 bits, and the old OSZACP bitmask in the upper 16
12925 bits. */
12926 assign(t1,
12927 binop(Iop_16HLto32,
12928 unop(Iop_32to16,
12929 mk_x86g_calculate_eflags_all()),
12930 getIReg(2, R_EAX)
12931 ));
12932 /* Call the helper fn, to get a new AX and OSZACP value, and
12933 poke both back into the guest state. Also pass the helper
12934 the actual opcode so it knows which of the 2 instructions it
12935 is doing the computation for. */
12936 assign(t2,
12937 mkIRExprCCall(
12938 Ity_I32, 0/*regparm*/, "x86g_calculate_aad_aam",
12939 &x86g_calculate_aad_aam,
12940 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
12941 ));
12942 putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
12943
12944 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
12945 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
12946 stmt( IRStmt_Put( OFFB_CC_DEP1,
12947 binop(Iop_And32,
12948 binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
12949 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
12950 | X86G_CC_MASK_A | X86G_CC_MASK_Z
12951 | X86G_CC_MASK_S| X86G_CC_MASK_O )
12952 )
12953 )
12954 );
12955 /* Set NDEP even though it isn't used. This makes
12956 redundant-PUT elimination of previous stores to this field
12957 work better. */
12958 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
12959
12960 DIP(opc == 0xD4 ? "aam\n" : "aad\n");
12961 break;
sewardj1c6f9912004-09-07 10:15:24 +000012962
12963 /* ------------------------ CWD/CDQ -------------------- */
12964
12965 case 0x98: /* CBW */
12966 if (sz == 4) {
12967 putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
12968 DIP("cwde\n");
12969 } else {
sewardj47341042004-09-19 11:55:46 +000012970 vassert(sz == 2);
12971 putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
12972 DIP("cbw\n");
sewardj1c6f9912004-09-07 10:15:24 +000012973 }
12974 break;
sewardj64e1d652004-07-12 14:00:46 +000012975
12976 case 0x99: /* CWD/CDQ */
12977 ty = szToITy(sz);
12978 putIReg(sz, R_EDX,
12979 binop(mkSizedOp(ty,Iop_Sar8),
12980 getIReg(sz, R_EAX),
sewardj9ee82862004-12-14 01:16:59 +000012981 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +000012982 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
12983 break;
12984
sewardjbdc7d212004-09-09 02:46:40 +000012985 /* ------------------------ FPU ops -------------------- */
12986
12987 case 0x9E: /* SAHF */
12988 codegen_SAHF();
12989 DIP("sahf\n");
12990 break;
12991
sewardj8dfdc8a2005-10-03 11:39:02 +000012992 case 0x9F: /* LAHF */
12993 codegen_LAHF();
12994 DIP("lahf\n");
12995 break;
12996
sewardjbdc7d212004-09-09 02:46:40 +000012997 case 0x9B: /* FWAIT */
12998 /* ignore? */
12999 DIP("fwait\n");
13000 break;
13001
sewardjd1725d12004-08-12 20:46:53 +000013002 case 0xD8:
13003 case 0xD9:
13004 case 0xDA:
13005 case 0xDB:
13006 case 0xDC:
13007 case 0xDD:
13008 case 0xDE:
13009 case 0xDF: {
sewardj52d04912005-07-03 00:52:48 +000013010 Int delta0 = delta;
sewardjd1725d12004-08-12 20:46:53 +000013011 Bool decode_OK = False;
13012 delta = dis_FPU ( &decode_OK, sorb, delta );
13013 if (!decode_OK) {
13014 delta = delta0;
13015 goto decode_failure;
13016 }
13017 break;
13018 }
sewardj0611d802004-07-11 02:37:54 +000013019
13020 /* ------------------------ INC & DEC ------------------ */
13021
13022 case 0x40: /* INC eAX */
13023 case 0x41: /* INC eCX */
13024 case 0x42: /* INC eDX */
13025 case 0x43: /* INC eBX */
13026 case 0x44: /* INC eSP */
13027 case 0x45: /* INC eBP */
13028 case 0x46: /* INC eSI */
13029 case 0x47: /* INC eDI */
13030 vassert(sz == 2 || sz == 4);
13031 ty = szToITy(sz);
13032 t1 = newTemp(ty);
13033 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
13034 getIReg(sz, (UInt)(opc - 0x40)),
13035 mkU(ty,1)) );
13036 setFlags_INC_DEC( True, t1, ty );
13037 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
13038 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
13039 break;
13040
13041 case 0x48: /* DEC eAX */
13042 case 0x49: /* DEC eCX */
13043 case 0x4A: /* DEC eDX */
13044 case 0x4B: /* DEC eBX */
13045 case 0x4C: /* DEC eSP */
13046 case 0x4D: /* DEC eBP */
13047 case 0x4E: /* DEC eSI */
13048 case 0x4F: /* DEC eDI */
13049 vassert(sz == 2 || sz == 4);
13050 ty = szToITy(sz);
13051 t1 = newTemp(ty);
13052 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
13053 getIReg(sz, (UInt)(opc - 0x48)),
13054 mkU(ty,1)) );
13055 setFlags_INC_DEC( False, t1, ty );
13056 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
13057 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
13058 break;
13059
13060 /* ------------------------ INT ------------------------ */
13061
sewardj322bfa02007-02-28 23:31:42 +000013062 case 0xCC: /* INT 3 */
sewardj0f500042007-08-29 09:09:17 +000013063 jmp_lit(Ijk_SigTRAP,((Addr32)guest_EIP_bbstart)+delta);
sewardj322bfa02007-02-28 23:31:42 +000013064 dres.whatNext = Dis_StopHere;
13065 DIP("int $0x3\n");
13066 break;
13067
sewardj0611d802004-07-11 02:37:54 +000013068 case 0xCD: /* INT imm8 */
13069 d32 = getIByte(delta); delta++;
sewardj0f500042007-08-29 09:09:17 +000013070
sewardjd660d412008-12-03 21:29:59 +000013071 /* For any of the cases where we emit a jump (that is, for all
13072 currently handled cases), it's important that all ArchRegs
13073 carry their up-to-date value at this point. So we declare an
13074 end-of-block here, which forces any TempRegs caching ArchRegs
13075 to be flushed. */
13076
sewardj0f500042007-08-29 09:09:17 +000013077 /* Handle int $0x40 .. $0x43 by synthesising a segfault and a
13078 restart of this instruction (hence the "-2" two lines below,
13079 to get the restart EIP to be this instruction. This is
13080 probably Linux-specific and it would be more correct to only
13081 do this if the VexAbiInfo says that is what we should do. */
13082 if (d32 >= 0x40 && d32 <= 0x43) {
13083 jmp_lit(Ijk_SigSEGV,((Addr32)guest_EIP_bbstart)+delta-2);
13084 dres.whatNext = Dis_StopHere;
13085 DIP("int $0x%x\n", (Int)d32);
13086 break;
13087 }
13088
sewardjd660d412008-12-03 21:29:59 +000013089 /* Handle int $0x80 (linux syscalls), int $0x81 and $0x82
sewardje86310f2009-03-19 22:21:40 +000013090 (darwin syscalls). As part of this, note where we are, so we
13091 can back up the guest to this point if the syscall needs to
13092 be restarted. */
sewardjd660d412008-12-03 21:29:59 +000013093 if (d32 == 0x80) {
sewardje86310f2009-03-19 22:21:40 +000013094 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13095 mkU32(guest_EIP_curr_instr) ) );
sewardjd660d412008-12-03 21:29:59 +000013096 jmp_lit(Ijk_Sys_int128,((Addr32)guest_EIP_bbstart)+delta);
13097 dres.whatNext = Dis_StopHere;
13098 DIP("int $0x80\n");
13099 break;
13100 }
13101 if (d32 == 0x81) {
sewardje86310f2009-03-19 22:21:40 +000013102 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13103 mkU32(guest_EIP_curr_instr) ) );
sewardjd660d412008-12-03 21:29:59 +000013104 jmp_lit(Ijk_Sys_int129,((Addr32)guest_EIP_bbstart)+delta);
13105 dres.whatNext = Dis_StopHere;
13106 DIP("int $0x81\n");
13107 break;
13108 }
13109 if (d32 == 0x82) {
sewardje86310f2009-03-19 22:21:40 +000013110 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13111 mkU32(guest_EIP_curr_instr) ) );
sewardjd660d412008-12-03 21:29:59 +000013112 jmp_lit(Ijk_Sys_int130,((Addr32)guest_EIP_bbstart)+delta);
13113 dres.whatNext = Dis_StopHere;
13114 DIP("int $0x82\n");
13115 break;
13116 }
13117
13118 /* none of the above */
13119 goto decode_failure;
sewardj0611d802004-07-11 02:37:54 +000013120
sewardj77b86be2004-07-11 13:28:24 +000013121 /* ------------------------ Jcond, byte offset --------- */
13122
13123 case 0xEB: /* Jb (jump, byte offset) */
sewardj9e6491a2005-07-02 19:24:10 +000013124 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardj77b86be2004-07-11 13:28:24 +000013125 delta++;
sewardjc716aea2006-01-17 01:48:46 +000013126 if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
sewardj984d9b12010-01-15 10:53:21 +000013127 dres.whatNext = Dis_ResteerU;
sewardj9e6491a2005-07-02 19:24:10 +000013128 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000013129 } else {
13130 jmp_lit(Ijk_Boring,d32);
sewardj9e6491a2005-07-02 19:24:10 +000013131 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000013132 }
sewardj77b86be2004-07-11 13:28:24 +000013133 DIP("jmp-8 0x%x\n", d32);
13134 break;
sewardj0611d802004-07-11 02:37:54 +000013135
13136 case 0xE9: /* Jv (jump, 16/32 offset) */
13137 vassert(sz == 4); /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000013138 d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta);
sewardj0611d802004-07-11 02:37:54 +000013139 delta += sz;
sewardjc716aea2006-01-17 01:48:46 +000013140 if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
sewardj984d9b12010-01-15 10:53:21 +000013141 dres.whatNext = Dis_ResteerU;
sewardj9e6491a2005-07-02 19:24:10 +000013142 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000013143 } else {
13144 jmp_lit(Ijk_Boring,d32);
sewardj9e6491a2005-07-02 19:24:10 +000013145 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000013146 }
sewardj0611d802004-07-11 02:37:54 +000013147 DIP("jmp 0x%x\n", d32);
13148 break;
sewardje87b4842004-07-10 12:23:30 +000013149
13150 case 0x70:
13151 case 0x71:
13152 case 0x72: /* JBb/JNAEb (jump below) */
13153 case 0x73: /* JNBb/JAEb (jump not below) */
13154 case 0x74: /* JZb/JEb (jump zero) */
13155 case 0x75: /* JNZb/JNEb (jump not zero) */
13156 case 0x76: /* JBEb/JNAb (jump below or equal) */
13157 case 0x77: /* JNBEb/JAb (jump not below or equal) */
13158 case 0x78: /* JSb (jump negative) */
13159 case 0x79: /* JSb (jump not negative) */
13160 case 0x7A: /* JP (jump parity even) */
13161 case 0x7B: /* JNP/JPO (jump parity odd) */
13162 case 0x7C: /* JLb/JNGEb (jump less) */
13163 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
13164 case 0x7E: /* JLEb/JNGb (jump less or equal) */
13165 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj984d9b12010-01-15 10:53:21 +000013166 { Int jmpDelta;
13167 HChar* comment = "";
13168 jmpDelta = (Int)getSDisp8(delta);
13169 vassert(-128 <= jmpDelta && jmpDelta < 128);
13170 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + jmpDelta;
sewardje87b4842004-07-10 12:23:30 +000013171 delta++;
sewardj984d9b12010-01-15 10:53:21 +000013172 if (resteerCisOk
13173 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000013174 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000013175 && jmpDelta < 0
13176 && resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
13177 /* Speculation: assume this backward branch is taken. So we
13178 need to emit a side-exit to the insn following this one,
13179 on the negation of the condition, and continue at the
sewardj0d925b12010-01-17 15:47:01 +000013180 branch target address (d32). If we wind up back at the
13181 first instruction of the trace, just stop; it's better to
13182 let the IR loop unroller handle that case. */
sewardjdbf550c2005-01-24 11:54:11 +000013183 stmt( IRStmt_Exit(
13184 mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
13185 Ijk_Boring,
sewardj9e6491a2005-07-02 19:24:10 +000013186 IRConst_U32(guest_EIP_bbstart+delta) ) );
sewardj984d9b12010-01-15 10:53:21 +000013187 dres.whatNext = Dis_ResteerC;
sewardj9e6491a2005-07-02 19:24:10 +000013188 dres.continueAt = (Addr64)(Addr32)d32;
sewardj984d9b12010-01-15 10:53:21 +000013189 comment = "(assumed taken)";
13190 }
13191 else
13192 if (resteerCisOk
13193 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000013194 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000013195 && jmpDelta >= 0
13196 && resteerOkFn( callback_opaque,
13197 (Addr64)(Addr32)(guest_EIP_bbstart+delta)) ) {
13198 /* Speculation: assume this forward branch is not taken. So
13199 we need to emit a side-exit to d32 (the dest) and continue
13200 disassembling at the insn immediately following this
13201 one. */
13202 stmt( IRStmt_Exit(
13203 mk_x86g_calculate_condition((X86Condcode)(opc - 0x70)),
13204 Ijk_Boring,
13205 IRConst_U32(d32) ) );
13206 dres.whatNext = Dis_ResteerC;
13207 dres.continueAt = (Addr64)(Addr32)(guest_EIP_bbstart+delta);
13208 comment = "(assumed not taken)";
13209 }
13210 else {
13211 /* Conservative default translation - end the block at this
13212 point. */
13213 jcc_01( (X86Condcode)(opc - 0x70),
13214 (Addr32)(guest_EIP_bbstart+delta), d32);
sewardj9e6491a2005-07-02 19:24:10 +000013215 dres.whatNext = Dis_StopHere;
sewardjdbf550c2005-01-24 11:54:11 +000013216 }
sewardj984d9b12010-01-15 10:53:21 +000013217 DIP("j%s-8 0x%x %s\n", name_X86Condcode(opc - 0x70), d32, comment);
sewardje87b4842004-07-10 12:23:30 +000013218 break;
sewardj984d9b12010-01-15 10:53:21 +000013219 }
sewardje87b4842004-07-10 12:23:30 +000013220
sewardjdc5d0842006-11-16 10:42:02 +000013221 case 0xE3: /* JECXZ (for JCXZ see above) */
sewardjbaa66082005-08-23 17:29:27 +000013222 if (sz != 4) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000013223 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardjdc5d0842006-11-16 10:42:02 +000013224 delta ++;
sewardj458a6f82004-08-25 12:46:02 +000013225 stmt( IRStmt_Exit(
sewardjdc5d0842006-11-16 10:42:02 +000013226 binop(Iop_CmpEQ32, getIReg(4,R_ECX), mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +000013227 Ijk_Boring,
sewardjdc5d0842006-11-16 10:42:02 +000013228 IRConst_U32(d32)
13229 ));
13230 DIP("jecxz 0x%x\n", d32);
sewardj458a6f82004-08-25 12:46:02 +000013231 break;
13232
sewardjbaa66082005-08-23 17:29:27 +000013233 case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
13234 case 0xE1: /* LOOPE disp8: decrement count, jump if count != 0 && ZF==1 */
13235 case 0xE2: /* LOOP disp8: decrement count, jump if count != 0 */
13236 { /* Again, the docs say this uses ECX/CX as a count depending on
13237 the address size override, not the operand one. Since we
13238 don't handle address size overrides, I guess that means
13239 ECX. */
13240 IRExpr* zbit = NULL;
13241 IRExpr* count = NULL;
13242 IRExpr* cond = NULL;
13243 HChar* xtra = NULL;
13244
13245 if (sz != 4) goto decode_failure;
13246 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13247 delta++;
13248 putIReg(4, R_ECX, binop(Iop_Sub32, getIReg(4,R_ECX), mkU32(1)));
13249
13250 count = getIReg(4,R_ECX);
13251 cond = binop(Iop_CmpNE32, count, mkU32(0));
13252 switch (opc) {
13253 case 0xE2:
13254 xtra = "";
13255 break;
13256 case 0xE1:
13257 xtra = "e";
13258 zbit = mk_x86g_calculate_condition( X86CondZ );
13259 cond = mkAnd1(cond, zbit);
13260 break;
13261 case 0xE0:
13262 xtra = "ne";
13263 zbit = mk_x86g_calculate_condition( X86CondNZ );
13264 cond = mkAnd1(cond, zbit);
13265 break;
13266 default:
13267 vassert(0);
13268 }
13269 stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U32(d32)) );
13270
13271 DIP("loop%s 0x%x\n", xtra, d32);
13272 break;
13273 }
sewardj1813dbe2004-07-28 17:09:04 +000013274
13275 /* ------------------------ IMUL ----------------------- */
13276
13277 case 0x69: /* IMUL Iv, Ev, Gv */
13278 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
13279 break;
13280 case 0x6B: /* IMUL Ib, Ev, Gv */
13281 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
13282 break;
sewardj0611d802004-07-11 02:37:54 +000013283
13284 /* ------------------------ MOV ------------------------ */
13285
13286 case 0x88: /* MOV Gb,Eb */
13287 delta = dis_mov_G_E(sorb, 1, delta);
13288 break;
sewardjc9a65702004-07-07 16:32:57 +000013289
13290 case 0x89: /* MOV Gv,Ev */
13291 delta = dis_mov_G_E(sorb, sz, delta);
13292 break;
13293
sewardjc2ac51e2004-07-12 01:03:26 +000013294 case 0x8A: /* MOV Eb,Gb */
13295 delta = dis_mov_E_G(sorb, 1, delta);
13296 break;
sewardje05c42c2004-07-08 20:25:10 +000013297
13298 case 0x8B: /* MOV Ev,Gv */
13299 delta = dis_mov_E_G(sorb, sz, delta);
13300 break;
13301
sewardje87b4842004-07-10 12:23:30 +000013302 case 0x8D: /* LEA M,Gv */
sewardje9460bd2005-01-28 13:45:42 +000013303 if (sz != 4)
13304 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000013305 modrm = getIByte(delta);
13306 if (epartIsReg(modrm))
sewardje9460bd2005-01-28 13:45:42 +000013307 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000013308 /* NOTE! this is the one place where a segment override prefix
13309 has no effect on the address calculation. Therefore we pass
13310 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +000013311 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
13312 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +000013313 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +000013314 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
13315 nameIReg(sz,gregOfRM(modrm)));
13316 break;
sewardje05c42c2004-07-08 20:25:10 +000013317
sewardj063f02f2004-10-20 12:36:12 +000013318 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
13319 delta = dis_mov_Sw_Ew(sorb, sz, delta);
13320 break;
13321
sewardj7df596b2004-12-06 14:29:12 +000013322 case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
13323 delta = dis_mov_Ew_Sw(sorb, delta);
13324 break;
13325
sewardj43852812004-10-16 23:10:08 +000013326 case 0xA0: /* MOV Ob,AL */
13327 sz = 1;
13328 /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +000013329 case 0xA1: /* MOV Ov,eAX */
13330 d32 = getUDisp32(delta); delta += 4;
13331 ty = szToITy(sz);
13332 addr = newTemp(Ity_I32);
13333 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13334 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
13335 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
13336 d32, nameIReg(sz,R_EAX));
13337 break;
13338
sewardj180e8b32004-07-29 01:40:11 +000013339 case 0xA2: /* MOV Ob,AL */
13340 sz = 1;
13341 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +000013342 case 0xA3: /* MOV eAX,Ov */
13343 d32 = getUDisp32(delta); delta += 4;
13344 ty = szToITy(sz);
13345 addr = newTemp(Ity_I32);
13346 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13347 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
13348 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
13349 sorbTxt(sorb), d32);
13350 break;
sewardje87b4842004-07-10 12:23:30 +000013351
sewardjc2ac51e2004-07-12 01:03:26 +000013352 case 0xB0: /* MOV imm,AL */
13353 case 0xB1: /* MOV imm,CL */
13354 case 0xB2: /* MOV imm,DL */
13355 case 0xB3: /* MOV imm,BL */
13356 case 0xB4: /* MOV imm,AH */
13357 case 0xB5: /* MOV imm,CH */
13358 case 0xB6: /* MOV imm,DH */
13359 case 0xB7: /* MOV imm,BH */
13360 d32 = getIByte(delta); delta += 1;
13361 putIReg(1, opc-0xB0, mkU8(d32));
13362 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
13363 break;
sewardj7ed22952004-07-29 00:09:58 +000013364
sewardje87b4842004-07-10 12:23:30 +000013365 case 0xB8: /* MOV imm,eAX */
13366 case 0xB9: /* MOV imm,eCX */
13367 case 0xBA: /* MOV imm,eDX */
13368 case 0xBB: /* MOV imm,eBX */
13369 case 0xBC: /* MOV imm,eSP */
13370 case 0xBD: /* MOV imm,eBP */
13371 case 0xBE: /* MOV imm,eSI */
13372 case 0xBF: /* MOV imm,eDI */
13373 d32 = getUDisp(sz,delta); delta += sz;
13374 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
13375 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
13376 break;
13377
sewardj77b86be2004-07-11 13:28:24 +000013378 case 0xC6: /* MOV Ib,Eb */
13379 sz = 1;
13380 goto do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +000013381 case 0xC7: /* MOV Iv,Ev */
13382 goto do_Mov_I_E;
13383
13384 do_Mov_I_E:
13385 modrm = getIByte(delta);
13386 if (epartIsReg(modrm)) {
13387 delta++; /* mod/rm byte */
13388 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000013389 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000013390 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
13391 nameIReg(sz,eregOfRM(modrm)));
sewardje87b4842004-07-10 12:23:30 +000013392 } else {
13393 addr = disAMode ( &alen, sorb, delta, dis_buf );
13394 delta += alen;
13395 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000013396 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000013397 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
13398 }
13399 break;
13400
sewardj1813dbe2004-07-28 17:09:04 +000013401 /* ------------------------ opl imm, A ----------------- */
13402
13403 case 0x04: /* ADD Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013404 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj1813dbe2004-07-28 17:09:04 +000013405 break;
sewardj77b86be2004-07-11 13:28:24 +000013406 case 0x05: /* ADD Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013407 delta = dis_op_imm_A( sz, False, Iop_Add8, True, delta, "add" );
sewardj77b86be2004-07-11 13:28:24 +000013408 break;
13409
sewardj940e8c92004-07-11 16:53:24 +000013410 case 0x0C: /* OR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013411 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000013412 break;
sewardj82292882004-07-27 00:15:59 +000013413 case 0x0D: /* OR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013414 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj82292882004-07-27 00:15:59 +000013415 break;
13416
sewardjeca20362005-08-24 09:22:39 +000013417 case 0x14: /* ADC Ib, AL */
13418 delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
13419 break;
sewardja718d5d2005-04-03 14:59:54 +000013420 case 0x15: /* ADC Iv, eAX */
sewardjeca20362005-08-24 09:22:39 +000013421 delta = dis_op_imm_A( sz, True, Iop_Add8, True, delta, "adc" );
sewardja718d5d2005-04-03 14:59:54 +000013422 break;
13423
sewardj2fbae082005-10-03 02:07:08 +000013424 case 0x1C: /* SBB Ib, AL */
13425 delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
13426 break;
13427 case 0x1D: /* SBB Iv, eAX */
13428 delta = dis_op_imm_A( sz, True, Iop_Sub8, True, delta, "sbb" );
13429 break;
13430
sewardj940e8c92004-07-11 16:53:24 +000013431 case 0x24: /* AND Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013432 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj940e8c92004-07-11 16:53:24 +000013433 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013434 case 0x25: /* AND Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013435 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardjc2ac51e2004-07-12 01:03:26 +000013436 break;
sewardj0611d802004-07-11 02:37:54 +000013437
13438 case 0x2C: /* SUB Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013439 delta = dis_op_imm_A( 1, False, Iop_Sub8, True, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000013440 break;
sewardj68511542004-07-28 00:15:44 +000013441 case 0x2D: /* SUB Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013442 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj68511542004-07-28 00:15:44 +000013443 break;
13444
sewardj1c6f9912004-09-07 10:15:24 +000013445 case 0x34: /* XOR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013446 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj1c6f9912004-09-07 10:15:24 +000013447 break;
sewardjcaca9d02004-07-28 07:11:32 +000013448 case 0x35: /* XOR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013449 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardjcaca9d02004-07-28 07:11:32 +000013450 break;
13451
sewardj0611d802004-07-11 02:37:54 +000013452 case 0x3C: /* CMP Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013453 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000013454 break;
13455 case 0x3D: /* CMP Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013456 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000013457 break;
13458
sewardj77b86be2004-07-11 13:28:24 +000013459 case 0xA8: /* TEST Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013460 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj77b86be2004-07-11 13:28:24 +000013461 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013462 case 0xA9: /* TEST Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013463 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardjc2ac51e2004-07-12 01:03:26 +000013464 break;
13465
sewardj1c6f9912004-09-07 10:15:24 +000013466 /* ------------------------ opl Ev, Gv ----------------- */
13467
sewardj89cd0932004-09-08 18:23:25 +000013468 case 0x02: /* ADD Eb,Gb */
13469 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
13470 break;
sewardj9334b0f2004-07-10 22:43:54 +000013471 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013472 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +000013473 break;
13474
sewardj7ed22952004-07-29 00:09:58 +000013475 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013476 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +000013477 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013478 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013479 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +000013480 break;
sewardj2fbae082005-10-03 02:07:08 +000013481
13482 case 0x12: /* ADC Eb,Gb */
13483 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
13484 break;
sewardjc4eaff32004-09-10 20:25:11 +000013485 case 0x13: /* ADC Ev,Gv */
13486 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
13487 break;
13488
sewardj2fbae082005-10-03 02:07:08 +000013489 case 0x1A: /* SBB Eb,Gb */
13490 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
13491 break;
sewardj180e8b32004-07-29 01:40:11 +000013492 case 0x1B: /* SBB Ev,Gv */
13493 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +000013494 break;
13495
sewardj1c6f9912004-09-07 10:15:24 +000013496 case 0x22: /* AND Eb,Gb */
13497 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
13498 break;
sewardj180e8b32004-07-29 01:40:11 +000013499 case 0x23: /* AND Ev,Gv */
13500 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
13501 break;
13502
13503 case 0x2A: /* SUB Eb,Gb */
13504 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
13505 break;
sewardj0611d802004-07-11 02:37:54 +000013506 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013507 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000013508 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013509
13510 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013511 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000013512 break;
sewardj1813dbe2004-07-28 17:09:04 +000013513 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013514 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +000013515 break;
13516
sewardjc2ac51e2004-07-12 01:03:26 +000013517 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013518 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +000013519 break;
sewardje90ad6a2004-07-10 19:02:10 +000013520 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013521 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000013522 break;
13523
sewardj0611d802004-07-11 02:37:54 +000013524 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013525 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +000013526 break;
sewardje05c42c2004-07-08 20:25:10 +000013527 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013528 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +000013529 break;
13530
sewardj180e8b32004-07-29 01:40:11 +000013531 /* ------------------------ opl Gv, Ev ----------------- */
13532
13533 case 0x00: /* ADD Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013534 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13535 Iop_Add8, True, 1, delta, "add" );
sewardj180e8b32004-07-29 01:40:11 +000013536 break;
sewardje05c42c2004-07-08 20:25:10 +000013537 case 0x01: /* ADD Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013538 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13539 Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +000013540 break;
13541
sewardj940e8c92004-07-11 16:53:24 +000013542 case 0x08: /* OR Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013543 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13544 Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000013545 break;
sewardj9334b0f2004-07-10 22:43:54 +000013546 case 0x09: /* OR Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013547 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13548 Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +000013549 break;
13550
sewardja2384712004-07-29 14:36:40 +000013551 case 0x10: /* ADC Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013552 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13553 Iop_Add8, True, 1, delta, "adc" );
sewardja2384712004-07-29 14:36:40 +000013554 break;
sewardjcaca9d02004-07-28 07:11:32 +000013555 case 0x11: /* ADC Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013556 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13557 Iop_Add8, True, sz, delta, "adc" );
sewardjcaca9d02004-07-28 07:11:32 +000013558 break;
13559
sewardja2384712004-07-29 14:36:40 +000013560 case 0x18: /* SBB Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013561 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13562 Iop_Sub8, True, 1, delta, "sbb" );
sewardja2384712004-07-29 14:36:40 +000013563 break;
sewardjcaca9d02004-07-28 07:11:32 +000013564 case 0x19: /* SBB Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013565 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13566 Iop_Sub8, True, sz, delta, "sbb" );
sewardjcaca9d02004-07-28 07:11:32 +000013567 break;
13568
sewardja2384712004-07-29 14:36:40 +000013569 case 0x20: /* AND Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013570 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13571 Iop_And8, True, 1, delta, "and" );
sewardja2384712004-07-29 14:36:40 +000013572 break;
sewardj0611d802004-07-11 02:37:54 +000013573 case 0x21: /* AND Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013574 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13575 Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +000013576 break;
13577
sewardj180e8b32004-07-29 01:40:11 +000013578 case 0x28: /* SUB Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013579 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13580 Iop_Sub8, True, 1, delta, "sub" );
sewardj180e8b32004-07-29 01:40:11 +000013581 break;
sewardje05c42c2004-07-08 20:25:10 +000013582 case 0x29: /* SUB Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013583 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13584 Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +000013585 break;
13586
sewardjc2ac51e2004-07-12 01:03:26 +000013587 case 0x30: /* XOR Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013588 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13589 Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000013590 break;
sewardje87b4842004-07-10 12:23:30 +000013591 case 0x31: /* XOR Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013592 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13593 Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +000013594 break;
13595
sewardj0611d802004-07-11 02:37:54 +000013596 case 0x38: /* CMP Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013597 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13598 Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000013599 break;
sewardje90ad6a2004-07-10 19:02:10 +000013600 case 0x39: /* CMP Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013601 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13602 Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000013603 break;
13604
sewardj9334b0f2004-07-10 22:43:54 +000013605 /* ------------------------ POP ------------------------ */
13606
13607 case 0x58: /* POP eAX */
13608 case 0x59: /* POP eCX */
13609 case 0x5A: /* POP eDX */
13610 case 0x5B: /* POP eBX */
13611 case 0x5D: /* POP eBP */
13612 case 0x5E: /* POP eSI */
13613 case 0x5F: /* POP eDI */
13614 case 0x5C: /* POP eSP */
13615 vassert(sz == 2 || sz == 4);
13616 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
13617 assign(t2, getIReg(4, R_ESP));
13618 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
13619 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
13620 putIReg(sz, opc-0x58, mkexpr(t1));
13621 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
13622 break;
13623
sewardja2384712004-07-29 14:36:40 +000013624 case 0x9D: /* POPF */
13625 vassert(sz == 2 || sz == 4);
sewardja2384712004-07-29 14:36:40 +000013626 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13627 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +000013628 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +000013629 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
sewardja2384712004-07-29 14:36:40 +000013630
sewardj0e9a0f52008-01-04 01:22:41 +000013631 /* Generate IR to set %EFLAGS{O,S,Z,A,C,P,D,ID,AC} from the
13632 value in t1. */
13633 set_EFLAGS_from_value( t1, True/*emit_AC_emwarn*/,
13634 ((Addr32)guest_EIP_bbstart)+delta );
sewardj6d269842005-08-06 11:45:02 +000013635
sewardja2384712004-07-29 14:36:40 +000013636 DIP("popf%c\n", nameISize(sz));
13637 break;
13638
sewardjbbdc6222004-12-15 18:43:39 +000013639 case 0x61: /* POPA */
13640 /* This is almost certainly wrong for sz==2. So ... */
13641 if (sz != 4) goto decode_failure;
13642
13643 /* t5 is the old %ESP value. */
13644 t5 = newTemp(Ity_I32);
13645 assign( t5, getIReg(4, R_ESP) );
13646
13647 /* Reload all the registers, except %esp. */
13648 putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
13649 putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
13650 putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
13651 putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
13652 /* ignore saved %ESP */
13653 putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
13654 putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
13655 putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
13656
13657 /* and move %ESP back up */
13658 putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
13659
sewardja3d1a662005-03-29 21:33:11 +000013660 DIP("popa%c\n", nameISize(sz));
sewardjbbdc6222004-12-15 18:43:39 +000013661 break;
sewardjfeeb8a82004-11-30 12:30:11 +000013662
13663 case 0x8F: /* POPL/POPW m32 */
sewardjfcff1782006-05-12 14:04:48 +000013664 { Int len;
13665 UChar rm = getIByte(delta);
sewardjfeeb8a82004-11-30 12:30:11 +000013666
13667 /* make sure this instruction is correct POP */
sewardjfcff1782006-05-12 14:04:48 +000013668 if (epartIsReg(rm) || gregOfRM(rm) != 0)
13669 goto decode_failure;
sewardjfeeb8a82004-11-30 12:30:11 +000013670 /* and has correct size */
sewardjfcff1782006-05-12 14:04:48 +000013671 if (sz != 4 && sz != 2)
13672 goto decode_failure;
13673 ty = szToITy(sz);
13674
13675 t1 = newTemp(Ity_I32); /* stack address */
13676 t3 = newTemp(ty); /* data */
sewardjfeeb8a82004-11-30 12:30:11 +000013677 /* set t1 to ESP: t1 = ESP */
13678 assign( t1, getIReg(4, R_ESP) );
13679 /* load M[ESP] to virtual register t3: t3 = M[t1] */
sewardjfcff1782006-05-12 14:04:48 +000013680 assign( t3, loadLE(ty, mkexpr(t1)) );
sewardjfeeb8a82004-11-30 12:30:11 +000013681
13682 /* increase ESP; must be done before the STORE. Intel manual says:
13683 If the ESP register is used as a base register for addressing
13684 a destination operand in memory, the POP instruction computes
13685 the effective address of the operand after it increments the
13686 ESP register.
13687 */
13688 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
13689
13690 /* resolve MODR/M */
13691 addr = disAMode ( &len, sorb, delta, dis_buf);
13692 storeLE( mkexpr(addr), mkexpr(t3) );
13693
sewardjfcff1782006-05-12 14:04:48 +000013694 DIP("pop%c %s\n", sz==2 ? 'w' : 'l', dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +000013695
13696 delta += len;
13697 break;
13698 }
13699
sewardj5c5f72c2006-03-18 11:29:25 +000013700 case 0x1F: /* POP %DS */
13701 dis_pop_segreg( R_DS, sz ); break;
13702 case 0x07: /* POP %ES */
13703 dis_pop_segreg( R_ES, sz ); break;
13704 case 0x17: /* POP %SS */
13705 dis_pop_segreg( R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +000013706
13707 /* ------------------------ PUSH ----------------------- */
13708
13709 case 0x50: /* PUSH eAX */
13710 case 0x51: /* PUSH eCX */
13711 case 0x52: /* PUSH eDX */
13712 case 0x53: /* PUSH eBX */
13713 case 0x55: /* PUSH eBP */
13714 case 0x56: /* PUSH eSI */
13715 case 0x57: /* PUSH eDI */
13716 case 0x54: /* PUSH eSP */
13717 /* This is the Right Way, in that the value to be pushed is
13718 established before %esp is changed, so that pushl %esp
13719 correctly pushes the old value. */
13720 vassert(sz == 2 || sz == 4);
13721 ty = sz==2 ? Ity_I16 : Ity_I32;
sewardj883b00b2004-09-11 09:30:24 +000013722 t1 = newTemp(ty); t2 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000013723 assign(t1, getIReg(sz, opc-0x50));
13724 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
13725 putIReg(4, R_ESP, mkexpr(t2) );
13726 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +000013727 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
13728 break;
13729
13730
sewardj0c12ea82004-07-12 08:18:16 +000013731 case 0x68: /* PUSH Iv */
13732 d32 = getUDisp(sz,delta); delta += sz;
13733 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +000013734 case 0x6A: /* PUSH Ib, sign-extended to sz */
13735 d32 = getSDisp8(delta); delta += 1;
13736 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +000013737 do_push_I:
13738 ty = szToITy(sz);
13739 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
13740 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
13741 putIReg(4, R_ESP, mkexpr(t1) );
sewardjc4255a02006-08-28 18:04:33 +000013742 /* stop mkU16 asserting if d32 is a negative 16-bit number
13743 (bug #132813) */
13744 if (ty == Ity_I16)
13745 d32 &= 0xFFFF;
sewardj0c12ea82004-07-12 08:18:16 +000013746 storeLE( mkexpr(t1), mkU(ty,d32) );
13747 DIP("push%c $0x%x\n", nameISize(sz), d32);
13748 break;
13749
sewardja2384712004-07-29 14:36:40 +000013750 case 0x9C: /* PUSHF */ {
sewardja2384712004-07-29 14:36:40 +000013751 vassert(sz == 2 || sz == 4);
sewardja2384712004-07-29 14:36:40 +000013752
13753 t1 = newTemp(Ity_I32);
13754 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
13755 putIReg(4, R_ESP, mkexpr(t1) );
13756
sewardjbc210942005-07-21 10:07:13 +000013757 /* Calculate OSZACP, and patch in fixed fields as per
13758 Intel docs.
13759 - bit 1 is always 1
13760 - bit 9 is Interrupt Enable (should always be 1 in user mode?)
13761 */
sewardja2384712004-07-29 14:36:40 +000013762 t2 = newTemp(Ity_I32);
sewardjbc210942005-07-21 10:07:13 +000013763 assign( t2, binop(Iop_Or32,
13764 mk_x86g_calculate_eflags_all(),
13765 mkU32( (1<<1)|(1<<9) ) ));
sewardja2384712004-07-29 14:36:40 +000013766
sewardjf9c74fe2004-12-16 02:54:54 +000013767 /* Patch in the D flag. This can simply be a copy of bit 10 of
13768 baseBlock[OFFB_DFLAG]. */
sewardja2384712004-07-29 14:36:40 +000013769 t3 = newTemp(Ity_I32);
13770 assign( t3, binop(Iop_Or32,
13771 mkexpr(t2),
13772 binop(Iop_And32,
sewardjf9c74fe2004-12-16 02:54:54 +000013773 IRExpr_Get(OFFB_DFLAG,Ity_I32),
sewardj5bd4d162004-11-10 13:02:48 +000013774 mkU32(1<<10)))
sewardja2384712004-07-29 14:36:40 +000013775 );
sewardj006a6a22004-10-26 00:50:52 +000013776
13777 /* And patch in the ID flag. */
13778 t4 = newTemp(Ity_I32);
13779 assign( t4, binop(Iop_Or32,
13780 mkexpr(t3),
13781 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +000013782 binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
sewardj006a6a22004-10-26 00:50:52 +000013783 mkU8(21)),
sewardj5bd4d162004-11-10 13:02:48 +000013784 mkU32(1<<21)))
sewardj006a6a22004-10-26 00:50:52 +000013785 );
13786
sewardj6d269842005-08-06 11:45:02 +000013787 /* And patch in the AC flag. */
13788 t5 = newTemp(Ity_I32);
13789 assign( t5, binop(Iop_Or32,
13790 mkexpr(t4),
13791 binop(Iop_And32,
13792 binop(Iop_Shl32, IRExpr_Get(OFFB_ACFLAG,Ity_I32),
13793 mkU8(18)),
13794 mkU32(1<<18)))
13795 );
13796
sewardja2384712004-07-29 14:36:40 +000013797 /* if sz==2, the stored value needs to be narrowed. */
13798 if (sz == 2)
sewardj6d269842005-08-06 11:45:02 +000013799 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t5)) );
sewardja2384712004-07-29 14:36:40 +000013800 else
sewardj6d269842005-08-06 11:45:02 +000013801 storeLE( mkexpr(t1), mkexpr(t5) );
sewardja2384712004-07-29 14:36:40 +000013802
13803 DIP("pushf%c\n", nameISize(sz));
13804 break;
13805 }
13806
sewardjbbdc6222004-12-15 18:43:39 +000013807 case 0x60: /* PUSHA */
13808 /* This is almost certainly wrong for sz==2. So ... */
13809 if (sz != 4) goto decode_failure;
13810
13811 /* This is the Right Way, in that the value to be pushed is
13812 established before %esp is changed, so that pusha
13813 correctly pushes the old %esp value. New value of %esp is
13814 pushed at start. */
13815 /* t0 is the %ESP value we're going to push. */
13816 t0 = newTemp(Ity_I32);
13817 assign( t0, getIReg(4, R_ESP) );
13818
13819 /* t5 will be the new %ESP value. */
13820 t5 = newTemp(Ity_I32);
13821 assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
13822
13823 /* Update guest state before prodding memory. */
13824 putIReg(4, R_ESP, mkexpr(t5));
13825
13826 /* Dump all the registers. */
13827 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
13828 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
13829 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
13830 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
13831 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
13832 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
13833 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
13834 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
13835
13836 DIP("pusha%c\n", nameISize(sz));
13837 break;
13838
sewardj5c5f72c2006-03-18 11:29:25 +000013839 case 0x0E: /* PUSH %CS */
13840 dis_push_segreg( R_CS, sz ); break;
13841 case 0x1E: /* PUSH %DS */
13842 dis_push_segreg( R_DS, sz ); break;
13843 case 0x06: /* PUSH %ES */
13844 dis_push_segreg( R_ES, sz ); break;
13845 case 0x16: /* PUSH %SS */
13846 dis_push_segreg( R_SS, sz ); break;
sewardj458a6f82004-08-25 12:46:02 +000013847
13848 /* ------------------------ SCAS et al ----------------- */
13849
13850 case 0xA4: /* MOVS, no REP prefix */
13851 case 0xA5:
sewardj9c3b25a2007-04-05 15:06:56 +000013852 if (sorb != 0)
13853 goto decode_failure; /* else dis_string_op asserts */
sewardj458a6f82004-08-25 12:46:02 +000013854 dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
13855 break;
13856
sewardj8d4d2232005-01-20 10:47:46 +000013857 case 0xA6: /* CMPSb, no REP prefix */
sewardj33b53542005-03-11 14:00:27 +000013858 case 0xA7:
sewardj9c3b25a2007-04-05 15:06:56 +000013859 if (sorb != 0)
13860 goto decode_failure; /* else dis_string_op asserts */
13861 dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
13862 break;
sewardj33b53542005-03-11 14:00:27 +000013863
sewardj883b00b2004-09-11 09:30:24 +000013864 case 0xAA: /* STOS, no REP prefix */
sewardj47341042004-09-19 11:55:46 +000013865 case 0xAB:
sewardj9c3b25a2007-04-05 15:06:56 +000013866 if (sorb != 0)
13867 goto decode_failure; /* else dis_string_op asserts */
sewardj883b00b2004-09-11 09:30:24 +000013868 dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
13869 break;
sewardj33b53542005-03-11 14:00:27 +000013870
sewardj10ca4eb2005-05-30 11:19:54 +000013871 case 0xAC: /* LODS, no REP prefix */
13872 case 0xAD:
sewardj9c3b25a2007-04-05 15:06:56 +000013873 if (sorb != 0)
13874 goto decode_failure; /* else dis_string_op asserts */
sewardj10ca4eb2005-05-30 11:19:54 +000013875 dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
13876 break;
sewardj2d4c3a02004-10-15 00:03:23 +000013877
13878 case 0xAE: /* SCAS, no REP prefix */
13879 case 0xAF:
sewardj9c3b25a2007-04-05 15:06:56 +000013880 if (sorb != 0)
13881 goto decode_failure; /* else dis_string_op asserts */
sewardj2d4c3a02004-10-15 00:03:23 +000013882 dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
13883 break;
sewardj64e1d652004-07-12 14:00:46 +000013884
13885
13886 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +000013887 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +000013888 DIP("cld\n");
13889 break;
13890
sewardj1813dbe2004-07-28 17:09:04 +000013891 case 0xFD: /* STD */
13892 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
13893 DIP("std\n");
13894 break;
13895
sewardjbc210942005-07-21 10:07:13 +000013896 case 0xF8: /* CLC */
13897 case 0xF9: /* STC */
13898 case 0xF5: /* CMC */
13899 t0 = newTemp(Ity_I32);
13900 t1 = newTemp(Ity_I32);
13901 assign( t0, mk_x86g_calculate_eflags_all() );
13902 switch (opc) {
13903 case 0xF8:
13904 assign( t1, binop(Iop_And32, mkexpr(t0),
13905 mkU32(~X86G_CC_MASK_C)));
13906 DIP("clc\n");
13907 break;
13908 case 0xF9:
13909 assign( t1, binop(Iop_Or32, mkexpr(t0),
13910 mkU32(X86G_CC_MASK_C)));
13911 DIP("stc\n");
13912 break;
13913 case 0xF5:
13914 assign( t1, binop(Iop_Xor32, mkexpr(t0),
13915 mkU32(X86G_CC_MASK_C)));
13916 DIP("cmc\n");
13917 break;
13918 default:
13919 vpanic("disInstr(x86)(clc/stc/cmc)");
13920 }
13921 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
13922 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13923 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
13924 /* Set NDEP even though it isn't used. This makes redundant-PUT
13925 elimination of previous stores to this field work better. */
13926 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13927 break;
sewardj82292882004-07-27 00:15:59 +000013928
sewardja384eb92007-11-16 02:30:38 +000013929 case 0xD6: /* SALC */
13930 t0 = newTemp(Ity_I32);
13931 t1 = newTemp(Ity_I32);
13932 assign( t0, binop(Iop_And32,
13933 mk_x86g_calculate_eflags_c(),
13934 mkU32(1)) );
13935 assign( t1, binop(Iop_Sar32,
13936 binop(Iop_Shl32, mkexpr(t0), mkU8(31)),
13937 mkU8(31)) );
13938 putIReg(1, R_EAX, unop(Iop_32to8, mkexpr(t1)) );
13939 DIP("salc\n");
13940 break;
13941
sewardj82292882004-07-27 00:15:59 +000013942 /* REPNE prefix insn */
13943 case 0xF2: {
sewardj068baa22008-05-11 10:11:58 +000013944 Addr32 eip_orig = guest_EIP_bbstart + delta_start;
sewardj9c3b25a2007-04-05 15:06:56 +000013945 if (sorb != 0) goto decode_failure;
sewardj82292882004-07-27 00:15:59 +000013946 abyte = getIByte(delta); delta++;
13947
13948 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj9e6491a2005-07-02 19:24:10 +000013949 dres.whatNext = Dis_StopHere;
sewardj82292882004-07-27 00:15:59 +000013950
13951 switch (abyte) {
13952 /* According to the Intel manual, "repne movs" should never occur, but
13953 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +000013954 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardjcea96622006-11-14 15:33:05 +000013955 case 0xA5:
13956 dis_REP_op ( X86CondNZ, dis_MOVS, sz, eip_orig,
13957 guest_EIP_bbstart+delta, "repne movs" );
13958 break;
sewardj842dfb42008-05-09 08:53:50 +000013959
13960 case 0xA6: sz = 1; /* REPNE CMP<sz> */
13961 case 0xA7:
13962 dis_REP_op ( X86CondNZ, dis_CMPS, sz, eip_orig,
13963 guest_EIP_bbstart+delta, "repne cmps" );
13964 break;
13965
sewardjb69a6fa2006-11-14 15:13:55 +000013966 case 0xAA: sz = 1; /* REPNE STOS<sz> */
13967 case 0xAB:
13968 dis_REP_op ( X86CondNZ, dis_STOS, sz, eip_orig,
13969 guest_EIP_bbstart+delta, "repne stos" );
13970 break;
13971
sewardj82292882004-07-27 00:15:59 +000013972 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000013973 case 0xAF:
sewardj2a9ad022004-11-25 02:46:58 +000013974 dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000013975 guest_EIP_bbstart+delta, "repne scas" );
sewardj82292882004-07-27 00:15:59 +000013976 break;
13977
13978 default:
13979 goto decode_failure;
13980 }
13981 break;
13982 }
sewardj64e1d652004-07-12 14:00:46 +000013983
13984 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
13985 for the rest, it means REP) */
13986 case 0xF3: {
sewardj068baa22008-05-11 10:11:58 +000013987 Addr32 eip_orig = guest_EIP_bbstart + delta_start;
sewardj9c3b25a2007-04-05 15:06:56 +000013988 if (sorb != 0) goto decode_failure;
sewardj64e1d652004-07-12 14:00:46 +000013989 abyte = getIByte(delta); delta++;
13990
13991 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj9e6491a2005-07-02 19:24:10 +000013992 dres.whatNext = Dis_StopHere;
sewardj64e1d652004-07-12 14:00:46 +000013993
13994 switch (abyte) {
13995 case 0xA4: sz = 1; /* REP MOVS<sz> */
13996 case 0xA5:
sewardj2a9ad022004-11-25 02:46:58 +000013997 dis_REP_op ( X86CondAlways, dis_MOVS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000013998 guest_EIP_bbstart+delta, "rep movs" );
sewardj64e1d652004-07-12 14:00:46 +000013999 break;
14000
14001 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000014002 case 0xA7:
sewardj2a9ad022004-11-25 02:46:58 +000014003 dis_REP_op ( X86CondZ, dis_CMPS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000014004 guest_EIP_bbstart+delta, "repe cmps" );
sewardj64e1d652004-07-12 14:00:46 +000014005 break;
14006
14007 case 0xAA: sz = 1; /* REP STOS<sz> */
14008 case 0xAB:
sewardj2a9ad022004-11-25 02:46:58 +000014009 dis_REP_op ( X86CondAlways, dis_STOS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000014010 guest_EIP_bbstart+delta, "rep stos" );
sewardj64e1d652004-07-12 14:00:46 +000014011 break;
sewardj576f3232006-04-12 17:30:46 +000014012
sewardjdfb038d2007-11-25 01:34:03 +000014013 case 0xAC: sz = 1; /* REP LODS<sz> */
14014 case 0xAD:
14015 dis_REP_op ( X86CondAlways, dis_LODS, sz, eip_orig,
14016 guest_EIP_bbstart+delta, "rep lods" );
14017 break;
14018
sewardj576f3232006-04-12 17:30:46 +000014019 case 0xAE: sz = 1; /* REPE SCAS<sz> */
14020 case 0xAF:
14021 dis_REP_op ( X86CondZ, dis_SCAS, sz, eip_orig,
14022 guest_EIP_bbstart+delta, "repe scas" );
14023 break;
sewardj43b8df12004-11-26 12:18:51 +000014024
14025 case 0x90: /* REP NOP (PAUSE) */
14026 /* a hint to the P4 re spin-wait loop */
14027 DIP("rep nop (P4 pause)\n");
sewardj7ec59f62005-03-12 16:47:18 +000014028 /* "observe" the hint. The Vex client needs to be careful not
14029 to cause very long delays as a result, though. */
sewardj9e6491a2005-07-02 19:24:10 +000014030 jmp_lit(Ijk_Yield, ((Addr32)guest_EIP_bbstart)+delta);
14031 dres.whatNext = Dis_StopHere;
sewardj43b8df12004-11-26 12:18:51 +000014032 break;
14033
sewardj7d3d3472005-08-12 23:51:31 +000014034 case 0xC3: /* REP RET -- same as normal ret? */
14035 dis_ret(0);
14036 dres.whatNext = Dis_StopHere;
14037 DIP("rep ret\n");
14038 break;
sewardj64e1d652004-07-12 14:00:46 +000014039
14040 default:
14041 goto decode_failure;
14042 }
14043 break;
14044 }
sewardj0611d802004-07-11 02:37:54 +000014045
14046 /* ------------------------ XCHG ----------------------- */
14047
sewardjc4356f02007-11-09 21:15:04 +000014048 /* XCHG reg,mem automatically asserts LOCK# even without a LOCK
sewardj1fb8c922009-07-12 12:56:53 +000014049 prefix; hence it must be translated with an IRCAS (at least, the
14050 memory variant). */
sewardj0611d802004-07-11 02:37:54 +000014051 case 0x86: /* XCHG Gb,Eb */
14052 sz = 1;
14053 /* Fall through ... */
14054 case 0x87: /* XCHG Gv,Ev */
14055 modrm = getIByte(delta);
14056 ty = szToITy(sz);
14057 t1 = newTemp(ty); t2 = newTemp(ty);
14058 if (epartIsReg(modrm)) {
sewardj5bd4d162004-11-10 13:02:48 +000014059 assign(t1, getIReg(sz, eregOfRM(modrm)));
14060 assign(t2, getIReg(sz, gregOfRM(modrm)));
14061 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
14062 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +000014063 delta++;
14064 DIP("xchg%c %s, %s\n",
14065 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
14066 nameIReg(sz,eregOfRM(modrm)));
14067 } else {
sewardje9d8a262009-07-01 08:06:34 +000014068 *expect_CAS = True;
sewardj0c12ea82004-07-12 08:18:16 +000014069 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj5bd4d162004-11-10 13:02:48 +000014070 assign( t1, loadLE(ty,mkexpr(addr)) );
14071 assign( t2, getIReg(sz,gregOfRM(modrm)) );
sewardje9d8a262009-07-01 08:06:34 +000014072 casLE( mkexpr(addr),
14073 mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
sewardj5bd4d162004-11-10 13:02:48 +000014074 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
14075 delta += alen;
sewardj0611d802004-07-11 02:37:54 +000014076 DIP("xchg%c %s, %s\n", nameISize(sz),
14077 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +000014078 }
14079 break;
sewardje87b4842004-07-10 12:23:30 +000014080
14081 case 0x90: /* XCHG eAX,eAX */
14082 DIP("nop\n");
14083 break;
sewardj64e1d652004-07-12 14:00:46 +000014084 case 0x91: /* XCHG eAX,eCX */
14085 case 0x92: /* XCHG eAX,eDX */
14086 case 0x93: /* XCHG eAX,eBX */
14087 case 0x94: /* XCHG eAX,eSP */
14088 case 0x95: /* XCHG eAX,eBP */
14089 case 0x96: /* XCHG eAX,eSI */
14090 case 0x97: /* XCHG eAX,eDI */
14091 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
14092 break;
14093
sewardj048de4d2006-11-12 22:25:21 +000014094 /* ------------------------ XLAT ----------------------- */
14095
14096 case 0xD7: /* XLAT */
14097 if (sz != 4) goto decode_failure; /* sz == 2 is also allowed (0x66) */
14098 putIReg(
14099 1,
14100 R_EAX/*AL*/,
14101 loadLE(Ity_I8,
14102 handleSegOverride(
14103 sorb,
14104 binop(Iop_Add32,
14105 getIReg(4, R_EBX),
14106 unop(Iop_8Uto32, getIReg(1, R_EAX/*AL*/))))));
14107
14108 DIP("xlat%c [ebx]\n", nameISize(sz));
14109 break;
sewardjd14c5702005-10-29 19:19:51 +000014110
14111 /* ------------------------ IN / OUT ----------------------- */
14112
14113 case 0xE4: /* IN imm8, AL */
14114 sz = 1;
14115 t1 = newTemp(Ity_I32);
14116 abyte = getIByte(delta); delta++;
14117 assign(t1, mkU32( abyte & 0xFF ));
14118 DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX));
14119 goto do_IN;
14120 case 0xE5: /* IN imm8, eAX */
14121 vassert(sz == 2 || sz == 4);
14122 t1 = newTemp(Ity_I32);
14123 abyte = getIByte(delta); delta++;
14124 assign(t1, mkU32( abyte & 0xFF ));
14125 DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX));
14126 goto do_IN;
14127 case 0xEC: /* IN %DX, AL */
14128 sz = 1;
14129 t1 = newTemp(Ity_I32);
14130 assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14131 DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14132 nameIReg(sz,R_EAX));
14133 goto do_IN;
14134 case 0xED: /* IN %DX, eAX */
14135 vassert(sz == 2 || sz == 4);
14136 t1 = newTemp(Ity_I32);
14137 assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14138 DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14139 nameIReg(sz,R_EAX));
14140 goto do_IN;
14141 do_IN: {
14142 /* At this point, sz indicates the width, and t1 is a 32-bit
14143 value giving port number. */
14144 IRDirty* d;
14145 vassert(sz == 1 || sz == 2 || sz == 4);
14146 ty = szToITy(sz);
14147 t2 = newTemp(Ity_I32);
14148 d = unsafeIRDirty_1_N(
14149 t2,
14150 0/*regparms*/,
14151 "x86g_dirtyhelper_IN",
14152 &x86g_dirtyhelper_IN,
14153 mkIRExprVec_2( mkexpr(t1), mkU32(sz) )
14154 );
14155 /* do the call, dumping the result in t2. */
14156 stmt( IRStmt_Dirty(d) );
14157 putIReg(sz, R_EAX, narrowTo( ty, mkexpr(t2) ) );
14158 break;
14159 }
14160
14161 case 0xE6: /* OUT AL, imm8 */
14162 sz = 1;
14163 t1 = newTemp(Ity_I32);
14164 abyte = getIByte(delta); delta++;
14165 assign( t1, mkU32( abyte & 0xFF ) );
14166 DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte);
14167 goto do_OUT;
14168 case 0xE7: /* OUT eAX, imm8 */
14169 vassert(sz == 2 || sz == 4);
14170 t1 = newTemp(Ity_I32);
14171 abyte = getIByte(delta); delta++;
14172 assign( t1, mkU32( abyte & 0xFF ) );
14173 DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte);
14174 goto do_OUT;
14175 case 0xEE: /* OUT AL, %DX */
14176 sz = 1;
14177 t1 = newTemp(Ity_I32);
14178 assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14179 DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14180 nameIReg(2,R_EDX));
14181 goto do_OUT;
14182 case 0xEF: /* OUT eAX, %DX */
14183 vassert(sz == 2 || sz == 4);
14184 t1 = newTemp(Ity_I32);
14185 assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14186 DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14187 nameIReg(2,R_EDX));
14188 goto do_OUT;
14189 do_OUT: {
14190 /* At this point, sz indicates the width, and t1 is a 32-bit
14191 value giving port number. */
14192 IRDirty* d;
14193 vassert(sz == 1 || sz == 2 || sz == 4);
14194 ty = szToITy(sz);
14195 d = unsafeIRDirty_0_N(
14196 0/*regparms*/,
14197 "x86g_dirtyhelper_OUT",
14198 &x86g_dirtyhelper_OUT,
14199 mkIRExprVec_3( mkexpr(t1),
14200 widenUto32( getIReg(sz, R_EAX) ),
14201 mkU32(sz) )
14202 );
14203 stmt( IRStmt_Dirty(d) );
14204 break;
14205 }
sewardj0611d802004-07-11 02:37:54 +000014206
14207 /* ------------------------ (Grp1 extensions) ---------- */
14208
sewardj792d7712008-10-31 21:27:38 +000014209 case 0x82: /* Grp1 Ib,Eb too. Apparently this is the same as
14210 case 0x80, but only in 32-bit mode. */
14211 /* fallthru */
sewardj0611d802004-07-11 02:37:54 +000014212 case 0x80: /* Grp1 Ib,Eb */
14213 modrm = getIByte(delta);
14214 am_sz = lengthAMode(delta);
14215 sz = 1;
14216 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +000014217 d32 = getUChar(delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014218 delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
sewardj0611d802004-07-11 02:37:54 +000014219 break;
sewardje05c42c2004-07-08 20:25:10 +000014220
14221 case 0x81: /* Grp1 Iv,Ev */
14222 modrm = getIByte(delta);
14223 am_sz = lengthAMode(delta);
14224 d_sz = sz;
14225 d32 = getUDisp(d_sz, delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014226 delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
sewardje05c42c2004-07-08 20:25:10 +000014227 break;
sewardjd1061ab2004-07-08 01:45:30 +000014228
14229 case 0x83: /* Grp1 Ib,Ev */
14230 modrm = getIByte(delta);
14231 am_sz = lengthAMode(delta);
14232 d_sz = 1;
14233 d32 = getSDisp8(delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014234 delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
sewardjd1061ab2004-07-08 01:45:30 +000014235 break;
14236
sewardjc2ac51e2004-07-12 01:03:26 +000014237 /* ------------------------ (Grp2 extensions) ---------- */
14238
sewardjd51dc812007-03-20 14:18:45 +000014239 case 0xC0: { /* Grp2 Ib,Eb */
14240 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000014241 modrm = getIByte(delta);
14242 am_sz = lengthAMode(delta);
14243 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000014244 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +000014245 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +000014246 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014247 mkU8(d32 & 0xFF), NULL, &decode_OK );
14248 if (!decode_OK)
14249 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000014250 break;
sewardjd51dc812007-03-20 14:18:45 +000014251 }
14252 case 0xC1: { /* Grp2 Ib,Ev */
14253 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000014254 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +000014255 am_sz = lengthAMode(delta);
14256 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000014257 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +000014258 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014259 mkU8(d32 & 0xFF), NULL, &decode_OK );
14260 if (!decode_OK)
14261 goto decode_failure;
sewardje90ad6a2004-07-10 19:02:10 +000014262 break;
sewardjd51dc812007-03-20 14:18:45 +000014263 }
14264 case 0xD0: { /* Grp2 1,Eb */
14265 Bool decode_OK = True;
sewardj180e8b32004-07-29 01:40:11 +000014266 modrm = getIByte(delta);
14267 am_sz = lengthAMode(delta);
14268 d_sz = 0;
14269 d32 = 1;
14270 sz = 1;
14271 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014272 mkU8(d32), NULL, &decode_OK );
14273 if (!decode_OK)
14274 goto decode_failure;
sewardj180e8b32004-07-29 01:40:11 +000014275 break;
sewardjd51dc812007-03-20 14:18:45 +000014276 }
14277 case 0xD1: { /* Grp2 1,Ev */
14278 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000014279 modrm = getUChar(delta);
14280 am_sz = lengthAMode(delta);
14281 d_sz = 0;
14282 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +000014283 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014284 mkU8(d32), NULL, &decode_OK );
14285 if (!decode_OK)
14286 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000014287 break;
sewardjd51dc812007-03-20 14:18:45 +000014288 }
14289 case 0xD2: { /* Grp2 CL,Eb */
14290 Bool decode_OK = True;
sewardj8c7f1ab2004-07-29 20:31:09 +000014291 modrm = getUChar(delta);
14292 am_sz = lengthAMode(delta);
14293 d_sz = 0;
14294 sz = 1;
14295 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014296 getIReg(1,R_ECX), "%cl", &decode_OK );
14297 if (!decode_OK)
14298 goto decode_failure;
sewardj8c7f1ab2004-07-29 20:31:09 +000014299 break;
sewardjd51dc812007-03-20 14:18:45 +000014300 }
14301 case 0xD3: { /* Grp2 CL,Ev */
14302 Bool decode_OK = True;
sewardj9334b0f2004-07-10 22:43:54 +000014303 modrm = getIByte(delta);
14304 am_sz = lengthAMode(delta);
14305 d_sz = 0;
14306 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014307 getIReg(1,R_ECX), "%cl", &decode_OK );
14308 if (!decode_OK)
14309 goto decode_failure;
sewardj9334b0f2004-07-10 22:43:54 +000014310 break;
sewardjd51dc812007-03-20 14:18:45 +000014311 }
sewardj9334b0f2004-07-10 22:43:54 +000014312
sewardj940e8c92004-07-11 16:53:24 +000014313 /* ------------------------ (Grp3 extensions) ---------- */
14314
sewardjd51dc812007-03-20 14:18:45 +000014315 case 0xF6: { /* Grp3 Eb */
14316 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014317 delta = dis_Grp3 ( sorb, pfx_lock, 1, delta, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014318 if (!decode_OK)
14319 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000014320 break;
sewardjd51dc812007-03-20 14:18:45 +000014321 }
14322 case 0xF7: { /* Grp3 Ev */
14323 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014324 delta = dis_Grp3 ( sorb, pfx_lock, sz, delta, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014325 if (!decode_OK)
14326 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000014327 break;
sewardjd51dc812007-03-20 14:18:45 +000014328 }
sewardj940e8c92004-07-11 16:53:24 +000014329
sewardjc2ac51e2004-07-12 01:03:26 +000014330 /* ------------------------ (Grp4 extensions) ---------- */
14331
sewardjd51dc812007-03-20 14:18:45 +000014332 case 0xFE: { /* Grp4 Eb */
14333 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014334 delta = dis_Grp4 ( sorb, pfx_lock, delta, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014335 if (!decode_OK)
14336 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000014337 break;
sewardjd51dc812007-03-20 14:18:45 +000014338 }
sewardj0611d802004-07-11 02:37:54 +000014339
14340 /* ------------------------ (Grp5 extensions) ---------- */
14341
sewardjd51dc812007-03-20 14:18:45 +000014342 case 0xFF: { /* Grp5 Ev */
14343 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014344 delta = dis_Grp5 ( sorb, pfx_lock, sz, delta, &dres, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014345 if (!decode_OK)
14346 goto decode_failure;
sewardj0611d802004-07-11 02:37:54 +000014347 break;
sewardjd51dc812007-03-20 14:18:45 +000014348 }
sewardje87b4842004-07-10 12:23:30 +000014349
14350 /* ------------------------ Escapes to 2-byte opcodes -- */
14351
14352 case 0x0F: {
14353 opc = getIByte(delta); delta++;
14354 switch (opc) {
14355
sewardj490ad382005-03-13 17:25:53 +000014356 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
14357
14358 case 0xBA: { /* Grp8 Ib,Ev */
14359 Bool decode_OK = False;
14360 modrm = getUChar(delta);
14361 am_sz = lengthAMode(delta);
14362 d32 = getSDisp8(delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014363 delta = dis_Grp8_Imm ( sorb, pfx_lock, delta, modrm,
14364 am_sz, sz, d32, &decode_OK );
sewardj490ad382005-03-13 17:25:53 +000014365 if (!decode_OK)
14366 goto decode_failure;
14367 break;
14368 }
sewardjce646f22004-08-31 23:55:54 +000014369
14370 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
14371
14372 case 0xBC: /* BSF Gv,Ev */
14373 delta = dis_bs_E_G ( sorb, sz, delta, True );
14374 break;
14375 case 0xBD: /* BSR Gv,Ev */
14376 delta = dis_bs_E_G ( sorb, sz, delta, False );
14377 break;
sewardj1c4208f2004-08-25 13:25:29 +000014378
14379 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
14380
14381 case 0xC8: /* BSWAP %eax */
14382 case 0xC9:
14383 case 0xCA:
sewardjb4666cf2004-10-23 00:21:50 +000014384 case 0xCB:
14385 case 0xCC:
14386 case 0xCD:
sewardj1c4208f2004-08-25 13:25:29 +000014387 case 0xCE:
sewardj1c6f9912004-09-07 10:15:24 +000014388 case 0xCF: /* BSWAP %edi */
sewardj1c4208f2004-08-25 13:25:29 +000014389 /* AFAICS from the Intel docs, this only exists at size 4. */
14390 vassert(sz == 4);
14391 t1 = newTemp(Ity_I32);
14392 t2 = newTemp(Ity_I32);
14393 assign( t1, getIReg(4, opc-0xC8) );
14394
14395 assign( t2,
14396 binop(Iop_Or32,
14397 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
14398 binop(Iop_Or32,
14399 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
14400 mkU32(0x00FF0000)),
14401 binop(Iop_Or32,
14402 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
14403 mkU32(0x0000FF00)),
14404 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
14405 mkU32(0x000000FF) )
14406 )))
14407 );
14408
14409 putIReg(4, opc-0xC8, mkexpr(t2));
sewardj1c4208f2004-08-25 13:25:29 +000014410 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
14411 break;
14412
sewardj1c6f9912004-09-07 10:15:24 +000014413 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
14414
14415 case 0xA3: /* BT Gv,Ev */
sewardj02834302010-07-29 18:10:51 +000014416 delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpNone );
sewardj1c6f9912004-09-07 10:15:24 +000014417 break;
sewardje6709112004-09-10 18:37:18 +000014418 case 0xB3: /* BTR Gv,Ev */
sewardj02834302010-07-29 18:10:51 +000014419 delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpReset );
sewardje6709112004-09-10 18:37:18 +000014420 break;
sewardj1c6f9912004-09-07 10:15:24 +000014421 case 0xAB: /* BTS Gv,Ev */
sewardj02834302010-07-29 18:10:51 +000014422 delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpSet );
sewardj1c6f9912004-09-07 10:15:24 +000014423 break;
sewardj4963a422004-10-14 23:34:03 +000014424 case 0xBB: /* BTC Gv,Ev */
sewardj02834302010-07-29 18:10:51 +000014425 delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpComp );
sewardj4963a422004-10-14 23:34:03 +000014426 break;
sewardj458a6f82004-08-25 12:46:02 +000014427
14428 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
14429
sewardj2d4c3a02004-10-15 00:03:23 +000014430 case 0x40:
14431 case 0x41:
sewardj458a6f82004-08-25 12:46:02 +000014432 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
14433 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
14434 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
14435 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
14436 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
14437 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
sewardjce646f22004-08-31 23:55:54 +000014438 case 0x48: /* CMOVSb (cmov negative) */
sewardj458a6f82004-08-25 12:46:02 +000014439 case 0x49: /* CMOVSb (cmov not negative) */
sewardj2d4c3a02004-10-15 00:03:23 +000014440 case 0x4A: /* CMOVP (cmov parity even) */
14441 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardj458a6f82004-08-25 12:46:02 +000014442 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
14443 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
14444 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
14445 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj2a9ad022004-11-25 02:46:58 +000014446 delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
sewardj458a6f82004-08-25 12:46:02 +000014447 break;
14448
14449 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
14450
sewardjc744e872004-08-26 11:24:39 +000014451 case 0xB0: /* CMPXCHG Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000014452 delta = dis_cmpxchg_G_E ( sorb, pfx_lock, 1, delta );
sewardjc744e872004-08-26 11:24:39 +000014453 break;
sewardj458a6f82004-08-25 12:46:02 +000014454 case 0xB1: /* CMPXCHG Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000014455 delta = dis_cmpxchg_G_E ( sorb, pfx_lock, sz, delta );
sewardj458a6f82004-08-25 12:46:02 +000014456 break;
sewardj300bb872005-08-12 23:04:48 +000014457
14458 case 0xC7: { /* CMPXCHG8B Gv (0F C7 /1) */
sewardje9d8a262009-07-01 08:06:34 +000014459 IRTemp expdHi = newTemp(Ity_I32);
14460 IRTemp expdLo = newTemp(Ity_I32);
14461 IRTemp dataHi = newTemp(Ity_I32);
14462 IRTemp dataLo = newTemp(Ity_I32);
14463 IRTemp oldHi = newTemp(Ity_I32);
14464 IRTemp oldLo = newTemp(Ity_I32);
sewardj300bb872005-08-12 23:04:48 +000014465 IRTemp flags_old = newTemp(Ity_I32);
14466 IRTemp flags_new = newTemp(Ity_I32);
sewardje9d8a262009-07-01 08:06:34 +000014467 IRTemp success = newTemp(Ity_I1);
14468
14469 /* Translate this using a DCAS, even if there is no LOCK
14470 prefix. Life is too short to bother with generating two
14471 different translations for the with/without-LOCK-prefix
14472 cases. */
14473 *expect_CAS = True;
sewardj300bb872005-08-12 23:04:48 +000014474
14475 /* Decode, and generate address. */
sewardje9d8a262009-07-01 08:06:34 +000014476 if (sz != 4) goto decode_failure;
sewardj300bb872005-08-12 23:04:48 +000014477 modrm = getIByte(delta);
14478 if (epartIsReg(modrm)) goto decode_failure;
14479 if (gregOfRM(modrm) != 1) goto decode_failure;
14480 addr = disAMode ( &alen, sorb, delta, dis_buf );
14481 delta += alen;
14482
sewardje9d8a262009-07-01 08:06:34 +000014483 /* Get the expected and new values. */
14484 assign( expdHi, getIReg(4,R_EDX) );
14485 assign( expdLo, getIReg(4,R_EAX) );
14486 assign( dataHi, getIReg(4,R_ECX) );
14487 assign( dataLo, getIReg(4,R_EBX) );
sewardj300bb872005-08-12 23:04:48 +000014488
sewardje9d8a262009-07-01 08:06:34 +000014489 /* Do the DCAS */
14490 stmt( IRStmt_CAS(
14491 mkIRCAS( oldHi, oldLo,
14492 Iend_LE, mkexpr(addr),
14493 mkexpr(expdHi), mkexpr(expdLo),
14494 mkexpr(dataHi), mkexpr(dataLo)
14495 )));
sewardj300bb872005-08-12 23:04:48 +000014496
sewardje9d8a262009-07-01 08:06:34 +000014497 /* success when oldHi:oldLo == expdHi:expdLo */
14498 assign( success,
sewardj1fb8c922009-07-12 12:56:53 +000014499 binop(Iop_CasCmpEQ32,
sewardje9d8a262009-07-01 08:06:34 +000014500 binop(Iop_Or32,
14501 binop(Iop_Xor32, mkexpr(oldHi), mkexpr(expdHi)),
14502 binop(Iop_Xor32, mkexpr(oldLo), mkexpr(expdLo))
14503 ),
14504 mkU32(0)
14505 ));
sewardj300bb872005-08-12 23:04:48 +000014506
sewardje9d8a262009-07-01 08:06:34 +000014507 /* If the DCAS is successful, that is to say oldHi:oldLo ==
14508 expdHi:expdLo, then put expdHi:expdLo back in EDX:EAX,
14509 which is where they came from originally. Both the actual
14510 contents of these two regs, and any shadow values, are
14511 unchanged. If the DCAS fails then we're putting into
14512 EDX:EAX the value seen in memory. */
14513 putIReg(4, R_EDX,
14514 IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(success)),
14515 mkexpr(oldHi),
14516 mkexpr(expdHi)
14517 ));
14518 putIReg(4, R_EAX,
14519 IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(success)),
14520 mkexpr(oldLo),
14521 mkexpr(expdLo)
14522 ));
sewardj300bb872005-08-12 23:04:48 +000014523
sewardje9d8a262009-07-01 08:06:34 +000014524 /* Copy the success bit into the Z flag and leave the others
14525 unchanged */
sewardj300bb872005-08-12 23:04:48 +000014526 assign( flags_old, widenUto32(mk_x86g_calculate_eflags_all()));
14527 assign(
14528 flags_new,
14529 binop(Iop_Or32,
14530 binop(Iop_And32, mkexpr(flags_old),
14531 mkU32(~X86G_CC_MASK_Z)),
14532 binop(Iop_Shl32,
14533 binop(Iop_And32,
sewardje9d8a262009-07-01 08:06:34 +000014534 unop(Iop_1Uto32, mkexpr(success)), mkU32(1)),
sewardj300bb872005-08-12 23:04:48 +000014535 mkU8(X86G_CC_SHIFT_Z)) ));
14536
14537 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
14538 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
14539 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14540 /* Set NDEP even though it isn't used. This makes
14541 redundant-PUT elimination of previous stores to this field
14542 work better. */
14543 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14544
14545 /* Sheesh. Aren't you glad it was me and not you that had to
14546 write and validate all this grunge? */
14547
14548 DIP("cmpxchg8b %s\n", dis_buf);
14549 break;
14550 }
14551
sewardj588ea762004-09-10 18:56:32 +000014552 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
14553
sewardj7cb49d72004-10-24 22:31:25 +000014554 case 0xA2: { /* CPUID */
14555 /* Uses dirty helper:
sewardj9df271d2004-12-31 22:37:42 +000014556 void dirtyhelper_CPUID_sse[012] ( VexGuestX86State* )
sewardj7cb49d72004-10-24 22:31:25 +000014557 declared to mod eax, wr ebx, ecx, edx
14558 */
sewardj9df271d2004-12-31 22:37:42 +000014559 IRDirty* d = NULL;
14560 HChar* fName = NULL;
14561 void* fAddr = NULL;
sewardj5117ce12006-01-27 21:20:15 +000014562 if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2) {
14563 fName = "x86g_dirtyhelper_CPUID_sse2";
14564 fAddr = &x86g_dirtyhelper_CPUID_sse2;
14565 }
14566 else
14567 if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE1) {
14568 fName = "x86g_dirtyhelper_CPUID_sse1";
14569 fAddr = &x86g_dirtyhelper_CPUID_sse1;
14570 }
14571 else
14572 if (archinfo->hwcaps == 0/*no SSE*/) {
14573 fName = "x86g_dirtyhelper_CPUID_sse0";
14574 fAddr = &x86g_dirtyhelper_CPUID_sse0;
14575 } else
14576 vpanic("disInstr(x86)(cpuid)");
14577
sewardj9df271d2004-12-31 22:37:42 +000014578 vassert(fName); vassert(fAddr);
14579 d = unsafeIRDirty_0_N ( 0/*regparms*/,
14580 fName, fAddr, mkIRExprVec_0() );
sewardj7cb49d72004-10-24 22:31:25 +000014581 /* declare guest state effects */
sewardjc5fc7aa2004-10-27 23:00:55 +000014582 d->needsBBP = True;
sewardj7cb49d72004-10-24 22:31:25 +000014583 d->nFxState = 4;
14584 d->fxState[0].fx = Ifx_Modify;
14585 d->fxState[0].offset = OFFB_EAX;
14586 d->fxState[0].size = 4;
14587 d->fxState[1].fx = Ifx_Write;
14588 d->fxState[1].offset = OFFB_EBX;
14589 d->fxState[1].size = 4;
sewardj32bfd3e2008-02-10 13:29:19 +000014590 d->fxState[2].fx = Ifx_Modify;
sewardj7cb49d72004-10-24 22:31:25 +000014591 d->fxState[2].offset = OFFB_ECX;
14592 d->fxState[2].size = 4;
14593 d->fxState[3].fx = Ifx_Write;
14594 d->fxState[3].offset = OFFB_EDX;
14595 d->fxState[3].size = 4;
14596 /* execute the dirty call, side-effecting guest state */
14597 stmt( IRStmt_Dirty(d) );
sewardj55860d82005-01-08 18:25:05 +000014598 /* CPUID is a serialising insn. So, just in case someone is
14599 using it as a memory fence ... */
sewardjc4356f02007-11-09 21:15:04 +000014600 stmt( IRStmt_MBE(Imbe_Fence) );
sewardj517a7d62004-10-25 09:52:18 +000014601 DIP("cpuid\n");
sewardj588ea762004-09-10 18:56:32 +000014602 break;
sewardj7cb49d72004-10-24 22:31:25 +000014603 }
14604
sewardj5bd4d162004-11-10 13:02:48 +000014605//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
14606//-- goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000014607//--
14608//-- t1 = newTemp(cb);
14609//-- t2 = newTemp(cb);
14610//-- t3 = newTemp(cb);
14611//-- t4 = newTemp(cb);
14612//-- uInstr0(cb, CALLM_S, 0);
14613//--
14614//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
14615//-- uInstr1(cb, PUSH, 4, TempReg, t1);
14616//--
14617//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
14618//-- uLiteral(cb, 0);
14619//-- uInstr1(cb, PUSH, 4, TempReg, t2);
14620//--
14621//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
14622//-- uLiteral(cb, 0);
14623//-- uInstr1(cb, PUSH, 4, TempReg, t3);
14624//--
14625//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
14626//-- uLiteral(cb, 0);
14627//-- uInstr1(cb, PUSH, 4, TempReg, t4);
14628//--
14629//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
14630//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
14631//--
14632//-- uInstr1(cb, POP, 4, TempReg, t4);
14633//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
14634//--
14635//-- uInstr1(cb, POP, 4, TempReg, t3);
14636//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
14637//--
14638//-- uInstr1(cb, POP, 4, TempReg, t2);
14639//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
14640//--
14641//-- uInstr1(cb, POP, 4, TempReg, t1);
14642//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
14643//--
14644//-- uInstr0(cb, CALLM_E, 0);
14645//-- DIP("cpuid\n");
14646//-- break;
14647//--
sewardj9334b0f2004-07-10 22:43:54 +000014648 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
14649
14650 case 0xB6: /* MOVZXb Eb,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014651 if (sz != 2 && sz != 4)
14652 goto decode_failure;
14653 delta = dis_movx_E_G ( sorb, delta, 1, sz, False );
sewardj9334b0f2004-07-10 22:43:54 +000014654 break;
sewardj6ba982f2006-05-03 17:57:15 +000014655
sewardj940e8c92004-07-11 16:53:24 +000014656 case 0xB7: /* MOVZXw Ew,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014657 if (sz != 4)
14658 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000014659 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
14660 break;
14661
sewardj0611d802004-07-11 02:37:54 +000014662 case 0xBE: /* MOVSXb Eb,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014663 if (sz != 2 && sz != 4)
14664 goto decode_failure;
14665 delta = dis_movx_E_G ( sorb, delta, 1, sz, True );
sewardj0611d802004-07-11 02:37:54 +000014666 break;
sewardj6ba982f2006-05-03 17:57:15 +000014667
sewardj7ed22952004-07-29 00:09:58 +000014668 case 0xBF: /* MOVSXw Ew,Gv */
sewardj33ca4ac2010-09-30 13:37:31 +000014669 if (sz != 4 && /* accept movsww, sigh, see #250799 */sz != 2)
sewardj6ba982f2006-05-03 17:57:15 +000014670 goto decode_failure;
sewardj33ca4ac2010-09-30 13:37:31 +000014671 delta = dis_movx_E_G ( sorb, delta, 2, sz, True );
sewardj7ed22952004-07-29 00:09:58 +000014672 break;
14673
sewardjc9a65702004-07-07 16:32:57 +000014674//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
14675//--
14676//-- case 0xC3: /* MOVNTI Gv,Ev */
14677//-- vg_assert(sz == 4);
14678//-- modrm = getUChar(eip);
14679//-- vg_assert(!epartIsReg(modrm));
14680//-- t1 = newTemp(cb);
14681//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
14682//-- pair = disAMode ( cb, sorb, eip, dis_buf );
14683//-- t2 = LOW24(pair);
14684//-- eip += HI8(pair);
14685//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
14686//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
14687//-- break;
sewardjcf780b42004-07-13 18:42:17 +000014688
14689 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
14690
14691 case 0xAF: /* IMUL Ev, Gv */
sewardj2a2ba8b2004-11-08 13:14:06 +000014692 delta = dis_mul_E_G ( sorb, sz, delta );
sewardjcf780b42004-07-13 18:42:17 +000014693 break;
sewardje87b4842004-07-10 12:23:30 +000014694
sewardjec387ca2006-08-01 18:36:25 +000014695 /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
14696
14697 case 0x1F:
14698 modrm = getUChar(delta);
14699 if (epartIsReg(modrm)) goto decode_failure;
14700 addr = disAMode ( &alen, sorb, delta, dis_buf );
14701 delta += alen;
14702 DIP("nop%c %s\n", nameISize(sz), dis_buf);
14703 break;
14704
sewardje87b4842004-07-10 12:23:30 +000014705 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
14706 case 0x80:
14707 case 0x81:
14708 case 0x82: /* JBb/JNAEb (jump below) */
14709 case 0x83: /* JNBb/JAEb (jump not below) */
14710 case 0x84: /* JZb/JEb (jump zero) */
14711 case 0x85: /* JNZb/JNEb (jump not zero) */
14712 case 0x86: /* JBEb/JNAb (jump below or equal) */
14713 case 0x87: /* JNBEb/JAb (jump not below or equal) */
14714 case 0x88: /* JSb (jump negative) */
14715 case 0x89: /* JSb (jump not negative) */
14716 case 0x8A: /* JP (jump parity even) */
14717 case 0x8B: /* JNP/JPO (jump parity odd) */
14718 case 0x8C: /* JLb/JNGEb (jump less) */
14719 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
14720 case 0x8E: /* JLEb/JNGb (jump less or equal) */
14721 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj984d9b12010-01-15 10:53:21 +000014722 { Int jmpDelta;
14723 HChar* comment = "";
14724 jmpDelta = (Int)getUDisp32(delta);
14725 d32 = (((Addr32)guest_EIP_bbstart)+delta+4) + jmpDelta;
sewardje87b4842004-07-10 12:23:30 +000014726 delta += 4;
sewardj984d9b12010-01-15 10:53:21 +000014727 if (resteerCisOk
14728 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000014729 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000014730 && jmpDelta < 0
14731 && resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
14732 /* Speculation: assume this backward branch is taken. So
14733 we need to emit a side-exit to the insn following this
14734 one, on the negation of the condition, and continue at
sewardj0d925b12010-01-17 15:47:01 +000014735 the branch target address (d32). If we wind up back at
14736 the first instruction of the trace, just stop; it's
14737 better to let the IR loop unroller handle that case.*/
sewardj984d9b12010-01-15 10:53:21 +000014738 stmt( IRStmt_Exit(
sewardj0d925b12010-01-17 15:47:01 +000014739 mk_x86g_calculate_condition((X86Condcode)
14740 (1 ^ (opc - 0x80))),
sewardj984d9b12010-01-15 10:53:21 +000014741 Ijk_Boring,
14742 IRConst_U32(guest_EIP_bbstart+delta) ) );
14743 dres.whatNext = Dis_ResteerC;
14744 dres.continueAt = (Addr64)(Addr32)d32;
14745 comment = "(assumed taken)";
14746 }
14747 else
14748 if (resteerCisOk
14749 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000014750 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000014751 && jmpDelta >= 0
14752 && resteerOkFn( callback_opaque,
14753 (Addr64)(Addr32)(guest_EIP_bbstart+delta)) ) {
14754 /* Speculation: assume this forward branch is not taken.
14755 So we need to emit a side-exit to d32 (the dest) and
14756 continue disassembling at the insn immediately
14757 following this one. */
14758 stmt( IRStmt_Exit(
14759 mk_x86g_calculate_condition((X86Condcode)(opc - 0x80)),
14760 Ijk_Boring,
14761 IRConst_U32(d32) ) );
14762 dres.whatNext = Dis_ResteerC;
14763 dres.continueAt = (Addr64)(Addr32)(guest_EIP_bbstart+delta);
14764 comment = "(assumed not taken)";
14765 }
14766 else {
14767 /* Conservative default translation - end the block at
14768 this point. */
14769 jcc_01( (X86Condcode)(opc - 0x80),
14770 (Addr32)(guest_EIP_bbstart+delta), d32);
14771 dres.whatNext = Dis_StopHere;
14772 }
14773 DIP("j%s-32 0x%x %s\n", name_X86Condcode(opc - 0x80), d32, comment);
sewardje87b4842004-07-10 12:23:30 +000014774 break;
sewardj984d9b12010-01-15 10:53:21 +000014775 }
sewardje87b4842004-07-10 12:23:30 +000014776
sewardj89cd0932004-09-08 18:23:25 +000014777 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
sewardj4ed64292005-08-23 19:24:29 +000014778 case 0x31: { /* RDTSC */
14779 IRTemp val = newTemp(Ity_I64);
14780 IRExpr** args = mkIRExprVec_0();
14781 IRDirty* d = unsafeIRDirty_1_N (
14782 val,
14783 0/*regparms*/,
14784 "x86g_dirtyhelper_RDTSC",
14785 &x86g_dirtyhelper_RDTSC,
14786 args
14787 );
sewardja5cbbdc2005-08-23 23:17:38 +000014788 /* execute the dirty call, dumping the result in val. */
14789 stmt( IRStmt_Dirty(d) );
14790 putIReg(4, R_EDX, unop(Iop_64HIto32, mkexpr(val)));
14791 putIReg(4, R_EAX, unop(Iop_64to32, mkexpr(val)));
14792 DIP("rdtsc\n");
14793 break;
sewardj4ed64292005-08-23 19:24:29 +000014794 }
sewardj77b86be2004-07-11 13:28:24 +000014795
sewardjb64821b2004-12-14 10:00:16 +000014796 /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
14797
14798 case 0xA1: /* POP %FS */
14799 dis_pop_segreg( R_FS, sz ); break;
14800 case 0xA9: /* POP %GS */
14801 dis_pop_segreg( R_GS, sz ); break;
14802
14803 case 0xA0: /* PUSH %FS */
14804 dis_push_segreg( R_FS, sz ); break;
14805 case 0xA8: /* PUSH %GS */
14806 dis_push_segreg( R_GS, sz ); break;
14807
sewardj77b86be2004-07-11 13:28:24 +000014808 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
14809 case 0x90:
14810 case 0x91:
14811 case 0x92: /* set-Bb/set-NAEb (jump below) */
14812 case 0x93: /* set-NBb/set-AEb (jump not below) */
14813 case 0x94: /* set-Zb/set-Eb (jump zero) */
14814 case 0x95: /* set-NZb/set-NEb (jump not zero) */
14815 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
14816 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
14817 case 0x98: /* set-Sb (jump negative) */
14818 case 0x99: /* set-Sb (jump not negative) */
14819 case 0x9A: /* set-P (jump parity even) */
14820 case 0x9B: /* set-NP (jump parity odd) */
14821 case 0x9C: /* set-Lb/set-NGEb (jump less) */
14822 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
14823 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
14824 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
sewardj5bd4d162004-11-10 13:02:48 +000014825 t1 = newTemp(Ity_I8);
sewardj2a9ad022004-11-25 02:46:58 +000014826 assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
sewardj77b86be2004-07-11 13:28:24 +000014827 modrm = getIByte(delta);
14828 if (epartIsReg(modrm)) {
14829 delta++;
sewardj5bd4d162004-11-10 13:02:48 +000014830 putIReg(1, eregOfRM(modrm), mkexpr(t1));
sewardj2a9ad022004-11-25 02:46:58 +000014831 DIP("set%s %s\n", name_X86Condcode(opc-0x90),
sewardj77b86be2004-07-11 13:28:24 +000014832 nameIReg(1,eregOfRM(modrm)));
14833 } else {
sewardj750f4072004-07-26 22:39:11 +000014834 addr = disAMode ( &alen, sorb, delta, dis_buf );
14835 delta += alen;
14836 storeLE( mkexpr(addr), mkexpr(t1) );
sewardj2a9ad022004-11-25 02:46:58 +000014837 DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +000014838 }
14839 break;
14840
sewardj180e8b32004-07-29 01:40:11 +000014841 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
14842
14843 case 0xA4: /* SHLDv imm8,Gv,Ev */
14844 modrm = getIByte(delta);
14845 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000014846 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj180e8b32004-07-29 01:40:11 +000014847 delta = dis_SHLRD_Gv_Ev (
14848 sorb, delta, modrm, sz,
14849 mkU8(getIByte(d32)), True, /* literal */
14850 dis_buf, True );
14851 break;
sewardja06e5562004-07-14 13:18:05 +000014852 case 0xA5: /* SHLDv %cl,Gv,Ev */
14853 modrm = getIByte(delta);
14854 delta = dis_SHLRD_Gv_Ev (
14855 sorb, delta, modrm, sz,
14856 getIReg(1,R_ECX), False, /* not literal */
14857 "%cl", True );
14858 break;
14859
sewardj68511542004-07-28 00:15:44 +000014860 case 0xAC: /* SHRDv imm8,Gv,Ev */
14861 modrm = getIByte(delta);
14862 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000014863 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj68511542004-07-28 00:15:44 +000014864 delta = dis_SHLRD_Gv_Ev (
14865 sorb, delta, modrm, sz,
14866 mkU8(getIByte(d32)), True, /* literal */
14867 dis_buf, False );
14868 break;
sewardja511afc2004-07-29 22:26:03 +000014869 case 0xAD: /* SHRDv %cl,Gv,Ev */
14870 modrm = getIByte(delta);
14871 delta = dis_SHLRD_Gv_Ev (
14872 sorb, delta, modrm, sz,
14873 getIReg(1,R_ECX), False, /* not literal */
14874 "%cl", False );
14875 break;
14876
sewardjf07ed032005-08-07 14:48:03 +000014877 /* =-=-=-=-=-=-=-=-=- SYSENTER -=-=-=-=-=-=-=-=-=-= */
14878
14879 case 0x34:
14880 /* Simple implementation needing a long explaination.
14881
14882 sysenter is a kind of syscall entry. The key thing here
14883 is that the return address is not known -- that is
14884 something that is beyond Vex's knowledge. So this IR
14885 forces a return to the scheduler, which can do what it
sewardj4fa325a2005-11-03 13:27:24 +000014886 likes to simulate the systenter, but it MUST set this
sewardjf07ed032005-08-07 14:48:03 +000014887 thread's guest_EIP field with the continuation address
14888 before resuming execution. If that doesn't happen, the
14889 thread will jump to address zero, which is probably
14890 fatal.
sewardje86310f2009-03-19 22:21:40 +000014891 */
14892
14893 /* Note where we are, so we can back up the guest to this
14894 point if the syscall needs to be restarted. */
14895 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
14896 mkU32(guest_EIP_curr_instr) ) );
sewardj4fa325a2005-11-03 13:27:24 +000014897 jmp_lit(Ijk_Sys_sysenter, 0/*bogus next EIP value*/);
sewardjf07ed032005-08-07 14:48:03 +000014898 dres.whatNext = Dis_StopHere;
14899 DIP("sysenter");
14900 break;
14901
sewardj464efa42004-11-19 22:17:29 +000014902 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
14903
sewardj0092e0d2006-03-06 13:35:42 +000014904 case 0xC0: { /* XADD Gb,Eb */
14905 Bool decodeOK;
sewardje9d8a262009-07-01 08:06:34 +000014906 delta = dis_xadd_G_E ( sorb, pfx_lock, 1, delta, &decodeOK );
sewardj0092e0d2006-03-06 13:35:42 +000014907 if (!decodeOK) goto decode_failure;
sewardj883b00b2004-09-11 09:30:24 +000014908 break;
sewardj0092e0d2006-03-06 13:35:42 +000014909 }
14910 case 0xC1: { /* XADD Gv,Ev */
14911 Bool decodeOK;
sewardje9d8a262009-07-01 08:06:34 +000014912 delta = dis_xadd_G_E ( sorb, pfx_lock, sz, delta, &decodeOK );
sewardj0092e0d2006-03-06 13:35:42 +000014913 if (!decodeOK) goto decode_failure;
14914 break;
14915 }
sewardj883b00b2004-09-11 09:30:24 +000014916
sewardjf13f37b2004-12-08 17:01:23 +000014917 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
sewardj464efa42004-11-19 22:17:29 +000014918
sewardj2b7a9202004-11-26 19:15:38 +000014919 case 0x71:
14920 case 0x72:
sewardj38a3f862005-01-13 15:06:51 +000014921 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardj2b7a9202004-11-26 19:15:38 +000014922
14923 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
14924 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj464efa42004-11-19 22:17:29 +000014925 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj2b7a9202004-11-26 19:15:38 +000014926 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +000014927
14928 case 0xFC:
14929 case 0xFD:
14930 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
14931
14932 case 0xEC:
14933 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
14934
14935 case 0xDC:
14936 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
14937
14938 case 0xF8:
14939 case 0xF9:
14940 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
14941
14942 case 0xE8:
14943 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
14944
14945 case 0xD8:
14946 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
14947
14948 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
14949 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
14950
sewardj4340dac2004-11-20 13:17:04 +000014951 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
14952
14953 case 0x74:
14954 case 0x75:
14955 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
14956
14957 case 0x64:
14958 case 0x65:
14959 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
14960
sewardj63ba4092004-11-21 12:30:18 +000014961 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
14962 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
14963 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
14964
14965 case 0x68:
14966 case 0x69:
14967 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
14968
14969 case 0x60:
14970 case 0x61:
14971 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
14972
14973 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
14974 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
14975 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
14976 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
14977
sewardj38a3f862005-01-13 15:06:51 +000014978 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000014979 case 0xF2:
sewardj38a3f862005-01-13 15:06:51 +000014980 case 0xF3:
sewardj8d14a592004-11-21 17:04:50 +000014981
sewardj38a3f862005-01-13 15:06:51 +000014982 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000014983 case 0xD2:
sewardj38a3f862005-01-13 15:06:51 +000014984 case 0xD3:
sewardj8d14a592004-11-21 17:04:50 +000014985
sewardj38a3f862005-01-13 15:06:51 +000014986 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
14987 case 0xE2:
sewardj464efa42004-11-19 22:17:29 +000014988 {
sewardj52d04912005-07-03 00:52:48 +000014989 Int delta0 = delta-1;
sewardj464efa42004-11-19 22:17:29 +000014990 Bool decode_OK = False;
sewardj38a3f862005-01-13 15:06:51 +000014991
14992 /* If sz==2 this is SSE, and we assume sse idec has
14993 already spotted those cases by now. */
14994 if (sz != 4)
14995 goto decode_failure;
14996
sewardj464efa42004-11-19 22:17:29 +000014997 delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
14998 if (!decode_OK) {
14999 delta = delta0;
15000 goto decode_failure;
15001 }
15002 break;
15003 }
15004
tome3aa0162011-08-11 14:43:12 +000015005 case 0x0E: /* FEMMS */
sewardj8d14a592004-11-21 17:04:50 +000015006 case 0x77: /* EMMS */
sewardj38a3f862005-01-13 15:06:51 +000015007 if (sz != 4)
15008 goto decode_failure;
sewardj4cb918d2004-12-03 19:43:31 +000015009 do_EMMS_preamble();
tome3aa0162011-08-11 14:43:12 +000015010 DIP("{f}emms\n");
sewardj8d14a592004-11-21 17:04:50 +000015011 break;
15012
sewardjb9dc2432010-06-07 16:22:22 +000015013 /* =-=-=-=-=-=-=-=-=- SGDT and SIDT =-=-=-=-=-=-=-=-=-=-= */
15014 case 0x01: /* 0F 01 /0 -- SGDT */
15015 /* 0F 01 /1 -- SIDT */
15016 {
15017 /* This is really revolting, but ... since each processor
15018 (core) only has one IDT and one GDT, just let the guest
15019 see it (pass-through semantics). I can't see any way to
15020 construct a faked-up value, so don't bother to try. */
15021 modrm = getUChar(delta);
15022 addr = disAMode ( &alen, sorb, delta, dis_buf );
15023 delta += alen;
15024 if (epartIsReg(modrm)) goto decode_failure;
15025 if (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)
15026 goto decode_failure;
15027 switch (gregOfRM(modrm)) {
15028 case 0: DIP("sgdt %s\n", dis_buf); break;
15029 case 1: DIP("sidt %s\n", dis_buf); break;
15030 default: vassert(0); /*NOTREACHED*/
15031 }
15032
15033 IRDirty* d = unsafeIRDirty_0_N (
15034 0/*regparms*/,
15035 "x86g_dirtyhelper_SxDT",
15036 &x86g_dirtyhelper_SxDT,
15037 mkIRExprVec_2( mkexpr(addr),
15038 mkU32(gregOfRM(modrm)) )
15039 );
15040 /* declare we're writing memory */
15041 d->mFx = Ifx_Write;
15042 d->mAddr = mkexpr(addr);
15043 d->mSize = 6;
15044 stmt( IRStmt_Dirty(d) );
15045 break;
15046 }
15047
sewardje87b4842004-07-10 12:23:30 +000015048 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
15049
15050 default:
15051 goto decode_failure;
15052 } /* switch (opc) for the 2-byte opcodes */
15053 goto decode_success;
15054 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +000015055
15056 /* ------------------------ ??? ------------------------ */
15057
15058 default:
sewardje87b4842004-07-10 12:23:30 +000015059 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +000015060 /* All decode failures end up here. */
sewardj52444cb2004-12-13 14:09:01 +000015061 vex_printf("vex x86->IR: unhandled instruction bytes: "
sewardjc9a65702004-07-07 16:32:57 +000015062 "0x%x 0x%x 0x%x 0x%x\n",
15063 (Int)getIByte(delta_start+0),
15064 (Int)getIByte(delta_start+1),
15065 (Int)getIByte(delta_start+2),
15066 (Int)getIByte(delta_start+3) );
sewardj52444cb2004-12-13 14:09:01 +000015067
sewardjb64821b2004-12-14 10:00:16 +000015068 /* Tell the dispatcher that this insn cannot be decoded, and so has
15069 not been executed, and (is currently) the next to be executed.
15070 EIP should be up-to-date since it made so at the start of each
15071 insn, but nevertheless be paranoid and update it again right
15072 now. */
sewardj9e6491a2005-07-02 19:24:10 +000015073 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr) ) );
15074 jmp_lit(Ijk_NoDecode, guest_EIP_curr_instr);
15075 dres.whatNext = Dis_StopHere;
15076 dres.len = 0;
sewardje9d8a262009-07-01 08:06:34 +000015077 /* We also need to say that a CAS is not expected now, regardless
15078 of what it might have been set to at the start of the function,
15079 since the IR that we've emitted just above (to synthesis a
15080 SIGILL) does not involve any CAS, and presumably no other IR has
15081 been emitted for this (non-decoded) insn. */
15082 *expect_CAS = False;
sewardj9e6491a2005-07-02 19:24:10 +000015083 return dres;
sewardj52444cb2004-12-13 14:09:01 +000015084
sewardjc9a65702004-07-07 16:32:57 +000015085 } /* switch (opc) for the main (primary) opcode switch. */
15086
sewardje87b4842004-07-10 12:23:30 +000015087 decode_success:
sewardjc9a65702004-07-07 16:32:57 +000015088 /* All decode successes end up here. */
15089 DIP("\n");
sewardj9e6491a2005-07-02 19:24:10 +000015090 dres.len = delta - delta_start;
15091 return dres;
sewardjc9a65702004-07-07 16:32:57 +000015092}
15093
15094#undef DIP
15095#undef DIS
15096
sewardj9e6491a2005-07-02 19:24:10 +000015097
15098/*------------------------------------------------------------*/
15099/*--- Top-level fn ---*/
15100/*------------------------------------------------------------*/
15101
15102/* Disassemble a single instruction into IR. The instruction
15103 is located in host memory at &guest_code[delta]. */
15104
sewardjdd40fdf2006-12-24 02:20:24 +000015105DisResult disInstr_X86 ( IRSB* irsb_IN,
sewardj9e6491a2005-07-02 19:24:10 +000015106 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +000015107 Bool (*resteerOkFn) ( void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +000015108 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +000015109 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000015110 UChar* guest_code_IN,
15111 Long delta,
15112 Addr64 guest_IP,
sewardja5f55da2006-04-30 23:37:32 +000015113 VexArch guest_arch,
sewardj9e6491a2005-07-02 19:24:10 +000015114 VexArchInfo* archinfo,
sewardjdd40fdf2006-12-24 02:20:24 +000015115 VexAbiInfo* abiinfo,
sewardj9e6491a2005-07-02 19:24:10 +000015116 Bool host_bigendian_IN )
15117{
sewardje9d8a262009-07-01 08:06:34 +000015118 Int i, x1, x2;
15119 Bool expect_CAS, has_CAS;
sewardj9e6491a2005-07-02 19:24:10 +000015120 DisResult dres;
15121
15122 /* Set globals (see top of this file) */
sewardja5f55da2006-04-30 23:37:32 +000015123 vassert(guest_arch == VexArchX86);
sewardj9e6491a2005-07-02 19:24:10 +000015124 guest_code = guest_code_IN;
sewardjdd40fdf2006-12-24 02:20:24 +000015125 irsb = irsb_IN;
sewardj9e6491a2005-07-02 19:24:10 +000015126 host_is_bigendian = host_bigendian_IN;
15127 guest_EIP_curr_instr = (Addr32)guest_IP;
15128 guest_EIP_bbstart = (Addr32)toUInt(guest_IP - delta);
15129
sewardje9d8a262009-07-01 08:06:34 +000015130 x1 = irsb_IN->stmts_used;
15131 expect_CAS = False;
15132 dres = disInstr_X86_WRK ( &expect_CAS, put_IP, resteerOkFn,
sewardj984d9b12010-01-15 10:53:21 +000015133 resteerCisOk,
sewardj02834302010-07-29 18:10:51 +000015134 callback_opaque,
15135 delta, archinfo, abiinfo );
sewardje9d8a262009-07-01 08:06:34 +000015136 x2 = irsb_IN->stmts_used;
15137 vassert(x2 >= x1);
15138
15139 /* See comment at the top of disInstr_X86_WRK for meaning of
15140 expect_CAS. Here, we (sanity-)check for the presence/absence of
15141 IRCAS as directed by the returned expect_CAS value. */
15142 has_CAS = False;
15143 for (i = x1; i < x2; i++) {
15144 if (irsb_IN->stmts[i]->tag == Ist_CAS)
15145 has_CAS = True;
15146 }
15147
15148 if (expect_CAS != has_CAS) {
15149 /* inconsistency detected. re-disassemble the instruction so as
15150 to generate a useful error message; then assert. */
15151 vex_traceflags |= VEX_TRACE_FE;
15152 dres = disInstr_X86_WRK ( &expect_CAS, put_IP, resteerOkFn,
sewardj984d9b12010-01-15 10:53:21 +000015153 resteerCisOk,
sewardj02834302010-07-29 18:10:51 +000015154 callback_opaque,
15155 delta, archinfo, abiinfo );
sewardje9d8a262009-07-01 08:06:34 +000015156 for (i = x1; i < x2; i++) {
15157 vex_printf("\t\t");
15158 ppIRStmt(irsb_IN->stmts[i]);
15159 vex_printf("\n");
15160 }
15161 /* Failure of this assertion is serious and denotes a bug in
15162 disInstr. */
15163 vpanic("disInstr_X86: inconsistency in LOCK prefix handling");
15164 }
sewardj9e6491a2005-07-02 19:24:10 +000015165
15166 return dres;
15167}
15168
15169
sewardjc9a65702004-07-07 16:32:57 +000015170/*--------------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +000015171/*--- end guest_x86_toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +000015172/*--------------------------------------------------------------------*/